lightning-sdk 0.1.56__py3-none-any.whl → 0.1.57__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 (39) hide show
  1. lightning_sdk/__init__.py +3 -2
  2. lightning_sdk/cli/ai_hub.py +61 -10
  3. lightning_sdk/cli/configure.py +110 -65
  4. lightning_sdk/cli/connect.py +32 -16
  5. lightning_sdk/cli/delete.py +81 -32
  6. lightning_sdk/cli/download.py +177 -90
  7. lightning_sdk/cli/entrypoint.py +44 -16
  8. lightning_sdk/cli/generate.py +48 -16
  9. lightning_sdk/cli/inspect.py +43 -3
  10. lightning_sdk/cli/list.py +130 -41
  11. lightning_sdk/cli/run.py +0 -6
  12. lightning_sdk/cli/teamspace_menu.py +1 -1
  13. lightning_sdk/helpers.py +20 -0
  14. lightning_sdk/job/job.py +1 -1
  15. lightning_sdk/lightning_cloud/openapi/__init__.py +5 -0
  16. lightning_sdk/lightning_cloud/openapi/api/data_connection_service_api.py +105 -0
  17. lightning_sdk/lightning_cloud/openapi/api/jobs_service_api.py +113 -0
  18. lightning_sdk/lightning_cloud/openapi/api/lit_logger_service_api.py +4 -4
  19. lightning_sdk/lightning_cloud/openapi/models/__init__.py +5 -0
  20. lightning_sdk/lightning_cloud/openapi/models/agents_id_body.py +105 -1
  21. lightning_sdk/lightning_cloud/openapi/models/deployments_id_body.py +29 -3
  22. lightning_sdk/lightning_cloud/openapi/models/id_visibility_body1.py +149 -0
  23. lightning_sdk/lightning_cloud/openapi/models/model_id_visibility_body.py +27 -1
  24. lightning_sdk/lightning_cloud/openapi/models/setup.py +149 -0
  25. lightning_sdk/lightning_cloud/openapi/models/v1_assistant.py +105 -1
  26. lightning_sdk/lightning_cloud/openapi/models/v1_deployment.py +29 -3
  27. lightning_sdk/lightning_cloud/openapi/models/v1_gcp_data_connection_setup.py +123 -0
  28. lightning_sdk/lightning_cloud/openapi/models/v1_job_spec.py +27 -1
  29. lightning_sdk/lightning_cloud/openapi/models/v1_setup_data_connection_response.py +123 -0
  30. lightning_sdk/lightning_cloud/openapi/models/v1_update_deployment_visibility_response.py +97 -0
  31. lightning_sdk/lightning_cloud/openapi/models/v1_update_metrics_stream_visibility_response.py +27 -1
  32. lightning_sdk/lightning_cloud/openapi/models/v1_update_model_visibility_response.py +27 -1
  33. lightning_sdk/lightning_cloud/openapi/models/v1_user_features.py +79 -1
  34. {lightning_sdk-0.1.56.dist-info → lightning_sdk-0.1.57.dist-info}/METADATA +2 -1
  35. {lightning_sdk-0.1.56.dist-info → lightning_sdk-0.1.57.dist-info}/RECORD +39 -34
  36. {lightning_sdk-0.1.56.dist-info → lightning_sdk-0.1.57.dist-info}/LICENSE +0 -0
  37. {lightning_sdk-0.1.56.dist-info → lightning_sdk-0.1.57.dist-info}/WHEEL +0 -0
  38. {lightning_sdk-0.1.56.dist-info → lightning_sdk-0.1.57.dist-info}/entry_points.txt +0 -0
  39. {lightning_sdk-0.1.56.dist-info → lightning_sdk-0.1.57.dist-info}/top_level.txt +0 -0
@@ -3,6 +3,7 @@ import re
3
3
  from pathlib import Path
4
4
  from typing import Optional
5
5
 
6
+ import click
6
7
  from rich.console import Console
7
8
 
8
9
  from lightning_sdk.api.lit_container_api import LitContainerApi
@@ -25,51 +26,7 @@ class _Downloads(_StudiosMenu, _TeamspacesMenu):
25
26
  This should have the format <ORGANIZATION-NAME>/<TEAMSPACE-NAME>/<MODEL-NAME>.
26
27
  download_dir: The directory where the Model should be downloaded.
27
28
  """
28
- download_model(
29
- name=name,
30
- download_dir=download_dir,
31
- progress_bar=True,
32
- )
33
-
34
- def _resolve_studio(self, studio: Optional[str]) -> Studio:
35
- user = _get_authed_user()
36
- # if no studio specify suggest/filter only user's studios
37
- possible_studios = self._get_possible_studios(user, is_owner=studio is None)
38
-
39
- try:
40
- if studio:
41
- team_name, studio_name = studio.split("/")
42
- options = [st for st in possible_studios if st["teamspace"] == team_name and st["name"] == studio_name]
43
- if len(options) == 1:
44
- selected_studio = self._get_studio_from_name(studio, possible_studios)
45
- # user can also use the partial studio name as secondary interactive selection
46
- else:
47
- # filter matching simple reg expressions or start with the team and studio name
48
- possible_studios = filter(
49
- lambda st: (re.match(team_name, st["teamspace"]) or team_name in st["teamspace"])
50
- and (re.match(studio_name, st["name"]) or studio_name in st["name"]),
51
- possible_studios,
52
- )
53
- if not possible_studios:
54
- raise ValueError(
55
- f"Could not find Studio like '{studio}', please consider update your filtering pattern."
56
- )
57
- selected_studio = self._get_studio_from_interactive_menu(list(possible_studios))
58
- else:
59
- selected_studio = self._get_studio_from_interactive_menu(possible_studios)
60
-
61
- except KeyboardInterrupt:
62
- raise KeyboardInterrupt from None
63
-
64
- # give user friendlier error message
65
- except Exception as e:
66
- raise StudioCliError(
67
- f"Could not find the given Studio {studio} to upload files to. "
68
- "Please contact Lightning AI directly to resolve this issue."
69
- ) from e
70
-
71
- with skip_studio_init():
72
- return Studio(**selected_studio)
29
+ model(name=name, download_dir=download_dir)
73
30
 
74
31
  def folder(self, path: str = "", studio: Optional[str] = None, local_path: str = ".") -> None:
75
32
  """Download a folder from a Studio.
@@ -84,27 +41,9 @@ class _Downloads(_StudiosMenu, _TeamspacesMenu):
84
41
  with filtered studios will be shown for final selection.
85
42
  local_path: The path to the directory you want to download the folder to.
86
43
  """
87
- local_path = Path(local_path)
88
- if not local_path.is_dir():
89
- raise NotADirectoryError(f"'{local_path}' is not a directory")
90
-
91
- resolved_studio = self._resolve_studio(studio)
44
+ folder(path=path, studio=studio, local_path=local_path)
92
45
 
93
- if not path:
94
- local_path /= resolved_studio.name
95
- path = ""
96
-
97
- try:
98
- if not path:
99
- raise FileNotFoundError()
100
- resolved_studio.download_folder(remote_path=path, target_path=str(local_path))
101
- except Exception as e:
102
- raise StudioCliError(
103
- f"Could not download the folder from the given Studio {studio}. "
104
- "Please contact Lightning AI directly to resolve this issue."
105
- ) from e
106
-
107
- def file(self, path: str = "", studio: Optional[str] = None, local_path: str = ".") -> None:
46
+ def file(self, path: str, studio: Optional[str] = None, local_path: str = ".") -> None:
108
47
  """Download a file from a Studio.
109
48
 
110
49
  Args:
@@ -115,25 +54,7 @@ class _Downloads(_StudiosMenu, _TeamspacesMenu):
115
54
  with filtered studios will be shown for final selection.
116
55
  local_path: The path to the directory you want to download the file to.
117
56
  """
118
- local_path = Path(local_path)
119
- if not local_path.is_dir():
120
- raise NotADirectoryError(f"'{local_path}' is not a directory")
121
-
122
- resolved_studio = self._resolve_studio(studio)
123
-
124
- if not path:
125
- local_path /= resolved_studio.name
126
- path = ""
127
-
128
- try:
129
- if not path:
130
- raise FileNotFoundError()
131
- resolved_studio.download_file(remote_path=path, file_path=str(local_path / os.path.basename(path)))
132
- except Exception as e:
133
- raise StudioCliError(
134
- f"Could not download the file from the given Studio {studio}. "
135
- "Please contact Lightning AI directly to resolve this issue."
136
- ) from e
57
+ file(path=path, studio=studio, local_path=local_path)
137
58
 
138
59
  def container(self, container: str, teamspace: Optional[str] = None, tag: str = "latest") -> None:
139
60
  """Download a docker container from a teamspace.
@@ -143,9 +64,175 @@ class _Downloads(_StudiosMenu, _TeamspacesMenu):
143
64
  teamspace: The name of the teamspace to download the container from.
144
65
  tag: The tag of the container to download.
145
66
  """
146
- console = Console()
147
- resolved_teamspace = self._resolve_teamspace(teamspace)
148
- with console.status("Downloading container..."):
149
- api = LitContainerApi()
150
- api.download_container(container, resolved_teamspace, tag)
151
- console.print("Container downloaded successfully", style="green")
67
+ download_container(container=container, teamspace=teamspace, tag=tag)
68
+
69
+
70
+ @click.group(name="download")
71
+ def download() -> None:
72
+ """Download resources from Lightning AI."""
73
+
74
+
75
+ # @download.command(name="model")
76
+ # @click.option(
77
+ # "--name",
78
+ # help=(
79
+ # "The name of the Model you want to download. "
80
+ # "This should have the format <ORGANIZATION-NAME>/<TEAMSPACE-NAME>/<MODEL-NAME>."
81
+ # ),
82
+ # )
83
+ # @click.option("--download-dir", default=".", help="The directory where the Model should be downloaded.")
84
+ def model(name: str, download_dir: str = ".") -> None:
85
+ """Download a Model."""
86
+ download_model(
87
+ name=name,
88
+ download_dir=download_dir,
89
+ progress_bar=True,
90
+ )
91
+
92
+
93
+ # @download.command(name="folder")
94
+ # @click.option(
95
+ # "--path",
96
+ # default="",
97
+ # help=(
98
+ # "The relative path within the Studio you want to download. "
99
+ # "If you leave it empty it will download whole studio and locally creates a "
100
+ # "new folder with the same name as the selected studio."
101
+ # ),
102
+ # )
103
+ # @click.option(
104
+ # "--studio",
105
+ # default=None,
106
+ # help=(
107
+ # "The name of the studio to upload to. "
108
+ # "Will show a menu with user's owned studios for selection if not specified. "
109
+ # "If provided, should be in the form of <TEAMSPACE-NAME>/<STUDIO-NAME> where the names are case-sensitive. "
110
+ # "The teamspace and studio names can be regular expressions to match, "
111
+ # "a menu filtered studios will be shown for final selection."
112
+ # ),
113
+ # )
114
+ # @click.option("--local-path", default=".", help="The path to the directory you want to download the folder to.")
115
+ def folder(path: str = "", studio: Optional[str] = None, local_path: str = ".") -> None:
116
+ """Download a folder from a Studio."""
117
+ local_path = Path(local_path)
118
+ if not local_path.is_dir():
119
+ raise NotADirectoryError(f"'{local_path}' is not a directory")
120
+
121
+ menu = _StudiosMenu()
122
+ resolved_studio = menu._resolve_studio(studio)
123
+
124
+ if not path:
125
+ local_path /= resolved_studio.name
126
+ path = ""
127
+
128
+ try:
129
+ if not path:
130
+ raise FileNotFoundError()
131
+ resolved_studio.download_folder(remote_path=path, target_path=str(local_path))
132
+ except Exception as e:
133
+ raise StudioCliError(
134
+ f"Could not download the folder from the given Studio {studio}. "
135
+ "Please contact Lightning AI directly to resolve this issue."
136
+ ) from e
137
+
138
+
139
+ # @download.command(name="file")
140
+ # @click.option(
141
+ # "--path",
142
+ # default="",
143
+ # help=(
144
+ # "The relative path within the Studio you want to download. "
145
+ # "If you leave it empty it will download whole studio and locally creates a new folder "
146
+ # "with the same name as the selected studio."
147
+ # ),
148
+ # )
149
+ # @click.option(
150
+ # "--studio",
151
+ # default=None,
152
+ # help=(
153
+ # "The name of the studio to upload to. "
154
+ # "Will show a menu with user's owned studios for selection if not specified. "
155
+ # "If provided, should be in the form of <TEAMSPACE-NAME>/<STUDIO-NAME> where the names are case-sensitive. "
156
+ # "The teamspace and studio names can be regular expressions to match, "
157
+ # "a menu filtered studios will be shown for final selection."
158
+ # ),
159
+ # )
160
+ # @click.option("--local-path", default=".", help="The path to the directory you want to download the folder to.")
161
+ def file(path: str = "", studio: Optional[str] = None, local_path: str = ".") -> None:
162
+ """Download a file from a Studio."""
163
+ local_path = Path(local_path)
164
+ if not local_path.is_dir():
165
+ raise NotADirectoryError(f"'{local_path}' is not a directory")
166
+
167
+ resolved_studio = _resolve_studio(studio)
168
+
169
+ if not path:
170
+ local_path /= resolved_studio.name
171
+ path = ""
172
+
173
+ try:
174
+ if not path:
175
+ raise FileNotFoundError()
176
+ resolved_studio.download_file(remote_path=path, file_path=str(local_path / os.path.basename(path)))
177
+ except Exception as e:
178
+ raise StudioCliError(
179
+ f"Could not download the file from the given Studio {studio}. "
180
+ "Please contact Lightning AI directly to resolve this issue."
181
+ ) from e
182
+
183
+
184
+ # @download.command(name="container")
185
+ # @click.argument("container")
186
+ # @click.argument("teamspace", default=None, help="The name of the teamspace to download the container from")
187
+ # @click.argument("tag", default="latest", show_default=True, help="The tag of the container to download.")
188
+ def download_container(container: str, teamspace: Optional[str] = None, tag: str = "latest") -> None:
189
+ """Download the docker container CONTAINER from a teamspace."""
190
+ console = Console()
191
+ menu = _TeamspacesMenu()
192
+ resolved_teamspace = menu._resolve_teamspace(teamspace)
193
+ with console.status("Downloading container..."):
194
+ api = LitContainerApi()
195
+ api.download_container(container, resolved_teamspace, tag)
196
+ console.print("Container downloaded successfully", style="green")
197
+
198
+
199
+ def _resolve_studio(studio: Optional[str]) -> Studio:
200
+ user = _get_authed_user()
201
+ # if no studio specify suggest/filter only user's studios
202
+ menu = _StudiosMenu()
203
+ possible_studios = menu._get_possible_studios(user, is_owner=studio is None)
204
+
205
+ try:
206
+ if studio:
207
+ team_name, studio_name = studio.split("/")
208
+ options = [st for st in possible_studios if st["teamspace"] == team_name and st["name"] == studio_name]
209
+ if len(options) == 1:
210
+ selected_studio = menu._get_studio_from_name(studio, possible_studios)
211
+ # user can also use the partial studio name as secondary interactive selection
212
+ else:
213
+ # filter matching simple reg expressions or start with the team and studio name
214
+ possible_studios = filter(
215
+ lambda st: (re.match(team_name, st["teamspace"]) or team_name in st["teamspace"])
216
+ and (re.match(studio_name, st["name"]) or studio_name in st["name"]),
217
+ possible_studios,
218
+ )
219
+ if not possible_studios:
220
+ raise ValueError(
221
+ f"Could not find Studio like '{studio}', please consider update your filtering pattern."
222
+ )
223
+ selected_studio = menu._get_studio_from_interactive_menu(list(possible_studios))
224
+ else:
225
+ selected_studio = menu._get_studio_from_interactive_menu(possible_studios)
226
+
227
+ except KeyboardInterrupt:
228
+ raise KeyboardInterrupt from None
229
+
230
+ # give user friendlier error message
231
+ except Exception as e:
232
+ raise StudioCliError(
233
+ f"Could not find the given Studio {studio} to upload files to. "
234
+ "Please contact Lightning AI directly to resolve this issue."
235
+ ) from e
236
+
237
+ with skip_studio_init():
238
+ return Studio(**selected_studio)
@@ -2,19 +2,20 @@ import sys
2
2
  from types import TracebackType
3
3
  from typing import Type
4
4
 
5
+ import click
5
6
  from fire import Fire
6
7
  from lightning_utilities.core.imports import RequirementCache
7
8
  from rich.console import Console
8
9
  from rich.panel import Panel
9
10
 
10
11
  from lightning_sdk.api.studio_api import _cloud_url
11
- from lightning_sdk.cli.ai_hub import _AIHub
12
- from lightning_sdk.cli.configure import _Configure
13
- from lightning_sdk.cli.connect import _Connect
14
- from lightning_sdk.cli.delete import _Delete
15
- from lightning_sdk.cli.download import _Downloads
16
- from lightning_sdk.cli.generate import _Generate
17
- from lightning_sdk.cli.inspect import _Inspect
12
+ from lightning_sdk.cli.ai_hub import _AIHub, aihub
13
+ from lightning_sdk.cli.configure import _Configure, configure
14
+ from lightning_sdk.cli.connect import _Connect, connect
15
+ from lightning_sdk.cli.delete import _Delete, delete
16
+ from lightning_sdk.cli.download import _Downloads, download
17
+ from lightning_sdk.cli.generate import _Generate, generate
18
+ from lightning_sdk.cli.inspect import _Inspect, inspect
18
19
  from lightning_sdk.cli.legacy import _LegacyLightningCLI
19
20
  from lightning_sdk.cli.list import _List
20
21
  from lightning_sdk.cli.run import _Run
@@ -52,18 +53,11 @@ class StudioCLI:
52
53
 
53
54
  def login(self) -> None:
54
55
  """Login to Lightning AI Studios."""
55
- auth = Auth()
56
- auth.clear()
57
-
58
- try:
59
- auth.authenticate()
60
- except ConnectionError:
61
- raise RuntimeError(f"Unable to connect to {_cloud_url()}. Please check your internet connection.") from None
56
+ return login()
62
57
 
63
58
  def logout(self) -> None:
64
59
  """Logout from Lightning AI Studios."""
65
- auth = Auth()
66
- auth.clear()
60
+ return logout()
67
61
 
68
62
 
69
63
  def _notify_exception(exception_type: Type[BaseException], value: BaseException, tb: TracebackType) -> None: # No
@@ -77,5 +71,39 @@ def main_cli() -> None:
77
71
  Fire(StudioCLI(), name="lightning")
78
72
 
79
73
 
74
+ @click.group(name="lightning", help="Command line interface (CLI) to interact with/manage Lightning AI Studios.")
75
+ def main_cli_click() -> None:
76
+ pass
77
+
78
+
79
+ # @main_cli_click.command
80
+ def login() -> None:
81
+ """Login to Lightning AI Studios."""
82
+ auth = Auth()
83
+ auth.clear()
84
+
85
+ try:
86
+ auth.authenticate()
87
+ except ConnectionError:
88
+ raise RuntimeError(f"Unable to connect to {_cloud_url()}. Please check your internet connection.") from None
89
+
90
+
91
+ # @main_cli_click.command
92
+ def logout() -> None:
93
+ """Logout from Lightning AI Studios."""
94
+ auth = Auth()
95
+ auth.clear()
96
+
97
+
98
+ # TODO: handle exception hook registration
99
+ main_cli_click.add_command(aihub)
100
+ main_cli_click.add_command(configure)
101
+ main_cli_click.add_command(connect)
102
+ main_cli_click.add_command(delete)
103
+ main_cli_click.add_command(download)
104
+ main_cli_click.add_command(generate)
105
+ main_cli_click.add_command(inspect)
106
+
107
+
80
108
  if __name__ == "__main__":
81
109
  main_cli()
@@ -1,24 +1,14 @@
1
1
  from typing import Optional
2
2
 
3
+ import click
3
4
  from rich.console import Console
4
5
 
5
6
  from lightning_sdk.cli.studios_menu import _StudiosMenu
6
7
 
7
8
 
8
- class _Generate(_StudiosMenu):
9
+ class _Generate:
9
10
  """Generate configs (such as ssh for studio) and print them to commandline."""
10
11
 
11
- @staticmethod
12
- def _generate_ssh_config(key_path: str) -> str:
13
- return f"""Host ssh.lightning.ai
14
- IdentityFile {key_path}
15
- IdentitiesOnly yes
16
- ServerAliveInterval 15
17
- ServerAliveCountMax 4
18
- StrictHostKeyChecking no
19
- UserKnownHostsFile=/dev/null
20
- """
21
-
22
12
  def ssh(self, name: Optional[str] = None, teamspace: Optional[str] = None) -> None:
23
13
  """Get SSH config entry for a studio.
24
14
 
@@ -28,8 +18,50 @@ class _Generate(_StudiosMenu):
28
18
  teamspace: The teamspace the studio is part of. Should be of format <OWNER>/<TEAMSPACE_NAME>.
29
19
  If not specified, tries to infer from the environment (e.g. when run from within a Studio.)
30
20
  """
31
- studio = self._get_studio(name=name, teamspace=teamspace)
21
+ ssh(name=name, teamspace=teamspace)
22
+
23
+
24
+ def _generate_ssh_config(key_path: str, host: str, user: str) -> str:
25
+ return f"""Host {host}
26
+ User {user}
27
+ Hostname ssh.lightning.ai
28
+ IdentityFile {key_path}
29
+ IdentitiesOnly yes
30
+ ServerAliveInterval 15
31
+ ServerAliveCountMax 4
32
+ StrictHostKeyChecking no
33
+ UserKnownHostsFile=/dev/null
34
+ """
35
+
36
+
37
+ @click.group(name="generate")
38
+ def generate() -> None:
39
+ """Generate configs (such as ssh for studio) and print them to commandline."""
40
+
41
+
42
+ # @generate.command(name="ssh")
43
+ # @click.option(
44
+ # "--name",
45
+ # default=None,
46
+ # help=(
47
+ # "The name of the studio to obtain SSH config. "
48
+ # "If not specified, tries to infer from the environment (e.g. when run from within a Studio.)"
49
+ # ),
50
+ # )
51
+ # @click.option(
52
+ # "--teamspace",
53
+ # default=None,
54
+ # help=(
55
+ # "The teamspace the studio is part of. "
56
+ # "Should be of format <OWNER>/<TEAMSPACE_NAME>. "
57
+ # "If not specified, tries to infer from the environment (e.g. when run from within a Studio.)"
58
+ # ),
59
+ # )
60
+ def ssh(name: Optional[str] = None, teamspace: Optional[str] = None) -> None:
61
+ """Get SSH config entry for a studio."""
62
+ menu = _StudiosMenu()
63
+ studio = menu._get_studio(name=name, teamspace=teamspace)
32
64
 
33
- # Print the SSH config
34
- conf = f"# ssh s_{studio._studio.id}@ssh.lightning.ai\n\n" + self._generate_ssh_config("~/.ssh/lightning_rsa")
35
- Console().print(conf)
65
+ conf = _generate_ssh_config(key_path="~/.ssh/lightning_rsa", user=f"s_{studio._studio.id}", host=studio.name)
66
+ # Print the SSH config
67
+ Console().print(f"# ssh s_{studio._studio.id}@ssh.lightning.ai\n\n" + conf)
@@ -1,11 +1,12 @@
1
1
  from typing import Optional
2
2
 
3
+ import click
3
4
  from rich.console import Console
4
5
 
5
6
  from lightning_sdk.cli.job_and_mmt_action import _JobAndMMTAction
6
7
 
7
8
 
8
- class _Inspect(_JobAndMMTAction):
9
+ class _Inspect:
9
10
  """Inspect resources of the Lightning AI platform to get additional details as JSON."""
10
11
 
11
12
  def job(self, name: Optional[str] = None, teamspace: Optional[str] = None) -> None:
@@ -18,7 +19,7 @@ class _Inspect(_JobAndMMTAction):
18
19
  If not specified can be selected interactively.
19
20
 
20
21
  """
21
- (super().job(name=name, teamspace=teamspace).json())
22
+ job(name=name, teamspace=teamspace)
22
23
 
23
24
  def mmt(self, name: Optional[str] = None, teamspace: Optional[str] = None) -> None:
24
25
  """Inspect a multi-machine job for further details as JSON.
@@ -30,4 +31,43 @@ class _Inspect(_JobAndMMTAction):
30
31
  If not specified can be selected interactively.
31
32
 
32
33
  """
33
- Console().print(super().mmt(name=name, teamspace=teamspace).json())
34
+ mmt(name=name, teamspace=teamspace)
35
+
36
+
37
+ @click.group(name="inspect")
38
+ def inspect() -> None:
39
+ """Inspect resources of the Lightning AI platform to get additional details as JSON."""
40
+
41
+
42
+ # @inspect.command(name="job")
43
+ # @click.option("--name", default=None, help="the name of the job. If not specified can be selected interactively.")
44
+ # @click.option(
45
+ # "--teamspace",
46
+ # default=None,
47
+ # help=(
48
+ # "the name of the teamspace the job lives in."
49
+ # "Should be specified as {teamspace_owner}/{teamspace_name} (e.g my-org/my-teamspace). "
50
+ # "If not specified can be selected interactively."
51
+ # ),
52
+ # )
53
+ def job(name: Optional[str] = None, teamspace: Optional[str] = None) -> None:
54
+ """Inspect a job for further details as JSON."""
55
+ menu = _JobAndMMTAction()
56
+ Console().print(menu.job(name=name, teamspace=teamspace).json())
57
+
58
+
59
+ # @inspect.command(name="mmt")
60
+ # @click.option("--name", default=None, help="the name of the job. If not specified can be selected interactively.")
61
+ # @click.option(
62
+ # "--teamspace",
63
+ # default=None,
64
+ # help=(
65
+ # "the name of the teamspace the job lives in."
66
+ # "Should be specified as {teamspace_owner}/{teamspace_name} (e.g my-org/my-teamspace). "
67
+ # "If not specified can be selected interactively."
68
+ # ),
69
+ # )
70
+ def mmt(name: Optional[str] = None, teamspace: Optional[str] = None) -> None:
71
+ """Inspect a multi-machine job for further details as JSON."""
72
+ menu = _JobAndMMTAction()
73
+ Console().print(menu.mmt(name=name, teamspace=teamspace).json())