qbraid-cli 0.8.0.dev1__py3-none-any.whl → 0.9.5__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.
Potentially problematic release.
This version of qbraid-cli might be problematic. Click here for more details.
- qbraid_cli/_version.py +2 -2
- qbraid_cli/account/__init__.py +11 -0
- qbraid_cli/account/app.py +65 -0
- qbraid_cli/admin/__init__.py +11 -0
- qbraid_cli/admin/app.py +59 -0
- qbraid_cli/admin/headers.py +235 -0
- qbraid_cli/admin/validation.py +32 -0
- qbraid_cli/chat/__init__.py +11 -0
- qbraid_cli/chat/app.py +76 -0
- qbraid_cli/configure/__init__.py +6 -1
- qbraid_cli/configure/actions.py +111 -0
- qbraid_cli/configure/app.py +34 -108
- qbraid_cli/devices/__init__.py +6 -1
- qbraid_cli/devices/app.py +43 -35
- qbraid_cli/devices/validation.py +26 -0
- qbraid_cli/envs/__init__.py +6 -1
- qbraid_cli/envs/activate.py +8 -5
- qbraid_cli/envs/app.py +116 -197
- qbraid_cli/envs/create.py +13 -109
- qbraid_cli/envs/data_handling.py +46 -0
- qbraid_cli/exceptions.py +3 -0
- qbraid_cli/files/__init__.py +11 -0
- qbraid_cli/files/app.py +118 -0
- qbraid_cli/handlers.py +46 -12
- qbraid_cli/jobs/__init__.py +6 -1
- qbraid_cli/jobs/app.py +76 -93
- qbraid_cli/jobs/toggle_braket.py +68 -74
- qbraid_cli/jobs/validation.py +94 -0
- qbraid_cli/kernels/__init__.py +6 -1
- qbraid_cli/kernels/app.py +74 -17
- qbraid_cli/main.py +66 -14
- qbraid_cli/pip/__init__.py +11 -0
- qbraid_cli/pip/app.py +50 -0
- qbraid_cli/pip/hooks.py +74 -0
- qbraid_cli/py.typed +0 -0
- qbraid_cli-0.9.5.dist-info/LICENSE +41 -0
- qbraid_cli-0.9.5.dist-info/METADATA +179 -0
- qbraid_cli-0.9.5.dist-info/RECORD +42 -0
- {qbraid_cli-0.8.0.dev1.dist-info → qbraid_cli-0.9.5.dist-info}/WHEEL +1 -1
- qbraid_cli/credits/__init__.py +0 -6
- qbraid_cli/credits/app.py +0 -30
- qbraid_cli-0.8.0.dev1.dist-info/METADATA +0 -136
- qbraid_cli-0.8.0.dev1.dist-info/RECORD +0 -25
- {qbraid_cli-0.8.0.dev1.dist-info → qbraid_cli-0.9.5.dist-info}/entry_points.txt +0 -0
- {qbraid_cli-0.8.0.dev1.dist-info → qbraid_cli-0.9.5.dist-info}/top_level.txt +0 -0
qbraid_cli/files/app.py
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# Copyright (c) 2024, qBraid Development Team
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
Module defining commands in the 'qbraid files' namespace.
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
import rich
|
|
13
|
+
import typer
|
|
14
|
+
|
|
15
|
+
from qbraid_cli.handlers import run_progress_task
|
|
16
|
+
|
|
17
|
+
files_app = typer.Typer(help="Manage qBraid cloud storage files.", no_args_is_help=True)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@files_app.command(name="upload")
|
|
21
|
+
def files_upload(
|
|
22
|
+
filepath: Path = typer.Argument(
|
|
23
|
+
...,
|
|
24
|
+
exists=True,
|
|
25
|
+
dir_okay=False,
|
|
26
|
+
resolve_path=True,
|
|
27
|
+
help="Local path to the file to upload.",
|
|
28
|
+
),
|
|
29
|
+
namespace: str = typer.Option(
|
|
30
|
+
"user",
|
|
31
|
+
"--namespace",
|
|
32
|
+
"-n",
|
|
33
|
+
help="Target qBraid namespace for the upload.",
|
|
34
|
+
),
|
|
35
|
+
object_path: str = typer.Option(
|
|
36
|
+
None,
|
|
37
|
+
"--object-path",
|
|
38
|
+
"-p",
|
|
39
|
+
help=("Target object path. " "Defaults to original filename in namespace root."),
|
|
40
|
+
),
|
|
41
|
+
overwrite: bool = typer.Option(
|
|
42
|
+
False,
|
|
43
|
+
"--overwrite",
|
|
44
|
+
"-o",
|
|
45
|
+
help="Overwrite existing file if it already exists in the target location.",
|
|
46
|
+
),
|
|
47
|
+
):
|
|
48
|
+
"""Upload a local file to qBraid storage."""
|
|
49
|
+
|
|
50
|
+
def upload_file() -> dict[str, Any]:
|
|
51
|
+
from qbraid_core.services.files import FileManagerClient
|
|
52
|
+
|
|
53
|
+
client = FileManagerClient()
|
|
54
|
+
data = client.upload_file(
|
|
55
|
+
filepath, namespace=namespace, object_path=object_path, overwrite=overwrite
|
|
56
|
+
)
|
|
57
|
+
return data
|
|
58
|
+
|
|
59
|
+
data: dict = run_progress_task(
|
|
60
|
+
upload_file, description="Uploading file...", include_error_traceback=False
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
rich.print("File uploaded successfully!")
|
|
64
|
+
namespace = data.get("namespace")
|
|
65
|
+
object_path = data.get("objectPath")
|
|
66
|
+
|
|
67
|
+
if namespace and object_path:
|
|
68
|
+
rich.print(f"\nNamespace: '{namespace}'")
|
|
69
|
+
rich.print(f"Object path: '{object_path}'")
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@files_app.command(name="download")
|
|
73
|
+
def files_download(
|
|
74
|
+
object_path: str = typer.Argument(
|
|
75
|
+
...,
|
|
76
|
+
help="The folder + filename describing the file to download.",
|
|
77
|
+
),
|
|
78
|
+
namespace: str = typer.Option(
|
|
79
|
+
"user",
|
|
80
|
+
"--namespace",
|
|
81
|
+
"-n",
|
|
82
|
+
help="Source qBraid namespace for the download.",
|
|
83
|
+
),
|
|
84
|
+
save_path: Path = typer.Option(
|
|
85
|
+
Path.cwd(),
|
|
86
|
+
"--save-path",
|
|
87
|
+
"-s",
|
|
88
|
+
resolve_path=True,
|
|
89
|
+
help="Local directory to save the downloaded file.",
|
|
90
|
+
),
|
|
91
|
+
overwrite: bool = typer.Option(
|
|
92
|
+
False,
|
|
93
|
+
"--overwrite",
|
|
94
|
+
"-o",
|
|
95
|
+
help="Overwrite existing file if it already exists in the target location.",
|
|
96
|
+
),
|
|
97
|
+
):
|
|
98
|
+
"""Download a file from qBraid storage."""
|
|
99
|
+
|
|
100
|
+
def download_file() -> Path:
|
|
101
|
+
from qbraid_core.services.files import FileManagerClient
|
|
102
|
+
|
|
103
|
+
client = FileManagerClient()
|
|
104
|
+
file_path = client.download_file(
|
|
105
|
+
object_path, namespace=namespace, save_path=save_path, overwrite=overwrite
|
|
106
|
+
)
|
|
107
|
+
return file_path
|
|
108
|
+
|
|
109
|
+
file_path: Path = run_progress_task(
|
|
110
|
+
download_file, description="Downloading file...", include_error_traceback=False
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
rich.print("File downloaded successfully!")
|
|
114
|
+
rich.print(f"Saved to: '{str(file_path)}'")
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
if __name__ == "__main__":
|
|
118
|
+
files_app()
|
qbraid_cli/handlers.py
CHANGED
|
@@ -1,20 +1,38 @@
|
|
|
1
|
+
# Copyright (c) 2024, qBraid Development Team
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
|
|
1
4
|
"""
|
|
2
5
|
Module providing application support utilities, including abstractions for error handling
|
|
3
6
|
and executing operations with progress tracking within the qBraid CLI.
|
|
4
7
|
|
|
5
8
|
"""
|
|
6
9
|
|
|
10
|
+
import os
|
|
7
11
|
import traceback
|
|
8
12
|
from pathlib import Path
|
|
9
|
-
from
|
|
13
|
+
from time import sleep
|
|
14
|
+
from typing import Any, Callable, Optional, Union
|
|
10
15
|
|
|
11
16
|
import typer
|
|
12
17
|
from rich.console import Console
|
|
13
|
-
from rich.progress import Progress, SpinnerColumn, TextColumn
|
|
18
|
+
from rich.progress import Progress, SpinnerColumn, TaskID, TextColumn
|
|
14
19
|
|
|
15
20
|
from .exceptions import DEFAULT_ERROR_MESSAGE, QbraidException
|
|
16
21
|
|
|
17
22
|
|
|
23
|
+
def _should_display_progress():
|
|
24
|
+
"""Whether to display rich progress UI."""
|
|
25
|
+
return os.getenv("QBRAID_CLI_SHOW_PROGRESS", "true").lower() in ["true", "1", "t", "y", "yes"]
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _update_completed_task(
|
|
29
|
+
progress: Progress, task_id: TaskID, success: bool = True, sleep_time: float = 0.15
|
|
30
|
+
):
|
|
31
|
+
status = "Done" if success else "Failed"
|
|
32
|
+
progress.update(task_id, completed=100, status=status)
|
|
33
|
+
sleep(sleep_time)
|
|
34
|
+
|
|
35
|
+
|
|
18
36
|
def handle_error(
|
|
19
37
|
error_type: Optional[str] = None, message: Optional[str] = None, include_traceback: bool = True
|
|
20
38
|
) -> None:
|
|
@@ -41,7 +59,11 @@ def handle_error(
|
|
|
41
59
|
full_message = f"\n{error_prefix} {message}\n"
|
|
42
60
|
if include_traceback:
|
|
43
61
|
tb_string = traceback.format_exc()
|
|
44
|
-
|
|
62
|
+
# TODO: find out reason for weird traceback emitted from
|
|
63
|
+
# qbraid jobs enable/disable when library not installed.
|
|
64
|
+
# For now, if matches, just don't print it.
|
|
65
|
+
if tb_string.strip() != "NoneType: None":
|
|
66
|
+
full_message += f"\n{tb_string}"
|
|
45
67
|
typer.echo(full_message, err=True)
|
|
46
68
|
raise typer.Exit(code=1)
|
|
47
69
|
|
|
@@ -72,6 +94,7 @@ def run_progress_task(
|
|
|
72
94
|
*args,
|
|
73
95
|
description: Optional[str] = None,
|
|
74
96
|
error_message: Optional[str] = None,
|
|
97
|
+
include_error_traceback: bool = True,
|
|
75
98
|
**kwargs,
|
|
76
99
|
) -> Any:
|
|
77
100
|
"""
|
|
@@ -89,6 +112,8 @@ def run_progress_task(
|
|
|
89
112
|
error_message (optional, str): Custom error message to display if the operation.
|
|
90
113
|
fails. Defaults to None, in which case the
|
|
91
114
|
exception's message is used.
|
|
115
|
+
include_error_traceback (bool): Whether to include the traceback in the error message.
|
|
116
|
+
Defaults to True.
|
|
92
117
|
**kwargs: Arbitrary keyword arguments for the operation.
|
|
93
118
|
|
|
94
119
|
Returns:
|
|
@@ -97,6 +122,13 @@ def run_progress_task(
|
|
|
97
122
|
Raises:
|
|
98
123
|
typer.Exit: If the operation fails, after displaying the error message using typer.secho.
|
|
99
124
|
"""
|
|
125
|
+
if not _should_display_progress():
|
|
126
|
+
try:
|
|
127
|
+
return operation(*args, **kwargs)
|
|
128
|
+
except Exception as err: # pylint: disable=broad-exception-caught
|
|
129
|
+
custom_message = error_message if error_message else str(err)
|
|
130
|
+
return handle_error(message=custom_message, include_traceback=include_error_traceback)
|
|
131
|
+
|
|
100
132
|
console = Console()
|
|
101
133
|
with Progress(
|
|
102
134
|
"[progress.description]{task.description}",
|
|
@@ -108,21 +140,23 @@ def run_progress_task(
|
|
|
108
140
|
task = progress.add_task(description, status="In Progress", total=None)
|
|
109
141
|
try:
|
|
110
142
|
result = operation(*args, **kwargs)
|
|
111
|
-
progress
|
|
143
|
+
_update_completed_task(progress, task, success=True)
|
|
112
144
|
return result
|
|
113
|
-
except Exception as
|
|
114
|
-
progress
|
|
115
|
-
custom_message = error_message if error_message else str(
|
|
116
|
-
return handle_error(message=custom_message)
|
|
145
|
+
except Exception as err: # pylint: disable=broad-exception-caught
|
|
146
|
+
_update_completed_task(progress, task, success=False)
|
|
147
|
+
custom_message = error_message if error_message else str(err)
|
|
148
|
+
return handle_error(message=custom_message, include_traceback=include_error_traceback)
|
|
149
|
+
finally:
|
|
150
|
+
progress.remove_task(task)
|
|
117
151
|
|
|
118
152
|
|
|
119
|
-
def _format_list_items(items:
|
|
153
|
+
def _format_list_items(items: list[str]) -> str:
|
|
120
154
|
"""
|
|
121
155
|
Formats a list of items as a string with values comma-separated and
|
|
122
156
|
each item surrounded by single quotes
|
|
123
157
|
|
|
124
158
|
Args:
|
|
125
|
-
items (
|
|
159
|
+
items (list[str]): The list of items to format.
|
|
126
160
|
|
|
127
161
|
Returns:
|
|
128
162
|
str: The formatted string.
|
|
@@ -131,14 +165,14 @@ def _format_list_items(items: List[str]) -> str:
|
|
|
131
165
|
|
|
132
166
|
|
|
133
167
|
def validate_item(
|
|
134
|
-
value: Optional[str], allowed_items:
|
|
168
|
+
value: Optional[str], allowed_items: list[str], item_type: str
|
|
135
169
|
) -> Union[str, None]:
|
|
136
170
|
"""
|
|
137
171
|
Generic item validation function.
|
|
138
172
|
|
|
139
173
|
Args:
|
|
140
174
|
value (optional, str): The value to validate.
|
|
141
|
-
allowed_items (
|
|
175
|
+
allowed_items (list[str]): A list of allowed items.
|
|
142
176
|
item_type (str): A description of the item type (e.g., 'provider', 'status', 'type') for
|
|
143
177
|
error messages.
|
|
144
178
|
|
qbraid_cli/jobs/__init__.py
CHANGED
qbraid_cli/jobs/app.py
CHANGED
|
@@ -1,128 +1,74 @@
|
|
|
1
|
+
# Copyright (c) 2024, qBraid Development Team
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
|
|
1
4
|
"""
|
|
2
5
|
Module defining commands in the 'qbraid jobs' namespace.
|
|
3
6
|
|
|
4
7
|
"""
|
|
5
8
|
|
|
6
|
-
import
|
|
7
|
-
from typing import Callable, Dict, Optional, Tuple
|
|
9
|
+
from typing import Any, Callable
|
|
8
10
|
|
|
9
11
|
import typer
|
|
10
12
|
from rich.console import Console
|
|
11
13
|
|
|
12
|
-
from qbraid_cli.handlers import handle_error, run_progress_task
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
QJOB_LIBS = ["braket"]
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def validate_library(value: str) -> str:
|
|
20
|
-
"""Validate quantum jobs library."""
|
|
21
|
-
return validate_item(value, QJOB_LIBS, "Library")
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def get_state(library: Optional[str] = None) -> Dict[str, Tuple[bool, bool]]:
|
|
25
|
-
"""Get the state of qBraid Quantum Jobs for the specified library."""
|
|
26
|
-
from qbraid.api.system import qbraid_jobs_state
|
|
14
|
+
from qbraid_cli.handlers import handle_error, run_progress_task
|
|
15
|
+
from qbraid_cli.jobs.toggle_braket import disable_braket, enable_braket
|
|
16
|
+
from qbraid_cli.jobs.validation import handle_jobs_state, run_progress_get_state, validate_library
|
|
27
17
|
|
|
28
|
-
|
|
18
|
+
jobs_app = typer.Typer(help="Manage qBraid quantum jobs.", no_args_is_help=True)
|
|
29
19
|
|
|
30
|
-
if library:
|
|
31
|
-
libraries_to_check = [library]
|
|
32
|
-
else:
|
|
33
|
-
libraries_to_check = QJOB_LIBS
|
|
34
20
|
|
|
35
|
-
|
|
36
|
-
state_values[lib] = qbraid_jobs_state(lib)
|
|
37
|
-
|
|
38
|
-
return state_values
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
def run_progress_get_state(library: Optional[str] = None) -> Dict[str, Tuple[bool, bool]]:
|
|
42
|
-
"""Run get state function with rich progress UI."""
|
|
43
|
-
return run_progress_task(
|
|
44
|
-
get_state,
|
|
45
|
-
library,
|
|
46
|
-
description="Collecting package metadata...",
|
|
47
|
-
error_message=f"Failed to collect {library} package metadata.",
|
|
48
|
-
)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
def handle_jobs_state(
|
|
52
|
-
library: str,
|
|
53
|
-
action: str, # 'enable' or 'disable'
|
|
54
|
-
action_callback: Callable[[], None],
|
|
55
|
-
) -> None:
|
|
56
|
-
"""Handle the common logic for enabling or disabling qBraid Quantum Jobs."""
|
|
57
|
-
state_values: Dict[str, Tuple[bool, bool]] = run_progress_get_state(library)
|
|
58
|
-
installed, enabled = state_values[library]
|
|
59
|
-
|
|
60
|
-
if not installed:
|
|
61
|
-
handle_error(message=f"{library} not installed.")
|
|
62
|
-
if (enabled and action == "enable") or (not enabled and action == "disable"):
|
|
63
|
-
action_color = "green" if enabled else "red"
|
|
64
|
-
console = Console()
|
|
65
|
-
console.print(
|
|
66
|
-
f"\nqBraid quantum jobs already [bold {action_color}]{action}d[/bold {action_color}] "
|
|
67
|
-
f"for [magenta]{library}[/magenta]."
|
|
68
|
-
)
|
|
69
|
-
console.print(
|
|
70
|
-
"To check the state of all quantum jobs libraries in this environment, "
|
|
71
|
-
"use: `[bold]qbraid jobs state[/bold]`"
|
|
72
|
-
)
|
|
73
|
-
raise typer.Exit()
|
|
74
|
-
|
|
75
|
-
action_callback() # Perform the specific enable/disable action
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
@app.command(name="enable")
|
|
21
|
+
@jobs_app.command(name="enable")
|
|
79
22
|
def jobs_enable(
|
|
80
23
|
library: str = typer.Argument(
|
|
81
24
|
..., help="Software library with quantum jobs support.", callback=validate_library
|
|
82
|
-
)
|
|
25
|
+
),
|
|
26
|
+
auto_confirm: bool = typer.Option(
|
|
27
|
+
False, "--yes", "-y", help="Automatically answer 'yes' to all prompts"
|
|
28
|
+
),
|
|
83
29
|
) -> None:
|
|
84
30
|
"""Enable qBraid Quantum Jobs."""
|
|
85
31
|
|
|
86
32
|
def enable_action():
|
|
87
33
|
if library == "braket":
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
enable_braket()
|
|
34
|
+
enable_braket(auto_confirm=auto_confirm)
|
|
91
35
|
else:
|
|
92
36
|
raise RuntimeError(f"Unsupported device library: '{library}'.")
|
|
93
37
|
|
|
94
38
|
handle_jobs_state(library, "enable", enable_action)
|
|
95
39
|
|
|
96
40
|
|
|
97
|
-
@
|
|
41
|
+
@jobs_app.command(name="disable")
|
|
98
42
|
def jobs_disable(
|
|
99
43
|
library: str = typer.Argument(
|
|
100
44
|
..., help="Software library with quantum jobs support.", callback=validate_library
|
|
101
|
-
)
|
|
45
|
+
),
|
|
46
|
+
auto_confirm: bool = typer.Option(
|
|
47
|
+
False, "--yes", "-y", help="Automatically answer 'yes' to all prompts"
|
|
48
|
+
),
|
|
102
49
|
) -> None:
|
|
103
50
|
"""Disable qBraid Quantum Jobs."""
|
|
104
51
|
|
|
105
52
|
def disable_action():
|
|
106
53
|
if library == "braket":
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
disable_braket()
|
|
54
|
+
disable_braket(auto_confirm=auto_confirm)
|
|
110
55
|
else:
|
|
111
56
|
raise RuntimeError(f"Unsupported device library: '{library}'.")
|
|
112
57
|
|
|
113
58
|
handle_jobs_state(library, "disable", disable_action)
|
|
114
59
|
|
|
115
60
|
|
|
116
|
-
@
|
|
61
|
+
@jobs_app.command(name="state")
|
|
117
62
|
def jobs_state(
|
|
118
63
|
library: str = typer.Argument(
|
|
119
64
|
default=None,
|
|
120
65
|
help="Optional: Specify a software library with quantum jobs support to check its status.",
|
|
121
66
|
callback=validate_library,
|
|
122
|
-
)
|
|
67
|
+
),
|
|
123
68
|
) -> None:
|
|
124
69
|
"""Display the state of qBraid Quantum Jobs for the current environment."""
|
|
125
|
-
|
|
70
|
+
result: tuple[str, dict[str, tuple[bool, bool]]] = run_progress_get_state(library)
|
|
71
|
+
python_exe, state_values = result
|
|
126
72
|
state_values = dict(sorted(state_values.items()))
|
|
127
73
|
|
|
128
74
|
console = Console()
|
|
@@ -130,40 +76,77 @@ def jobs_state(
|
|
|
130
76
|
max_lib_length = max((len(lib) for lib in state_values.keys()), default=len(header_1))
|
|
131
77
|
padding = max_lib_length + 9
|
|
132
78
|
|
|
133
|
-
|
|
134
|
-
console.print(f"\n{header_1:<{padding}}{header_2}", style="bold")
|
|
135
|
-
|
|
79
|
+
output = ""
|
|
136
80
|
for lib, (installed, enabled) in state_values.items():
|
|
137
81
|
state_str = (
|
|
138
82
|
"[green]enabled"
|
|
139
83
|
if enabled and installed
|
|
140
84
|
else "[red]disabled" if installed else "[grey70]unavailable"
|
|
141
85
|
)
|
|
142
|
-
|
|
86
|
+
output += f"{lib:<{padding-1}} {state_str}\n"
|
|
87
|
+
|
|
88
|
+
console.print(f"Executable: {python_exe}")
|
|
89
|
+
console.print(f"\n{header_1:<{padding}}{header_2}", style="bold")
|
|
90
|
+
console.print(output)
|
|
143
91
|
|
|
144
92
|
|
|
145
|
-
@
|
|
93
|
+
@jobs_app.command(name="list")
|
|
146
94
|
def jobs_list(
|
|
147
95
|
limit: int = typer.Option(
|
|
148
96
|
10, "--limit", "-l", help="Limit the maximum number of results returned"
|
|
149
|
-
)
|
|
97
|
+
),
|
|
150
98
|
) -> None:
|
|
151
99
|
"""List qBraid Quantum Jobs."""
|
|
152
100
|
|
|
153
|
-
def import_jobs() ->
|
|
154
|
-
from
|
|
155
|
-
|
|
101
|
+
def import_jobs() -> tuple[Any, Callable]:
|
|
102
|
+
from qbraid_core.services.quantum import QuantumClient, process_job_data
|
|
103
|
+
|
|
104
|
+
client = QuantumClient()
|
|
156
105
|
|
|
157
|
-
return
|
|
106
|
+
return client, process_job_data
|
|
158
107
|
|
|
159
|
-
result:
|
|
160
|
-
|
|
108
|
+
result: tuple[Any, Callable] = run_progress_task(import_jobs)
|
|
109
|
+
client, process_job_data = result
|
|
110
|
+
# https://github.com/qBraid/api/issues/644
|
|
111
|
+
# raw_data = client.search_jobs(query={"numResults": limit})
|
|
112
|
+
raw_data = client.search_jobs(query={})
|
|
113
|
+
job_data, msg = process_job_data(raw_data)
|
|
114
|
+
job_data = job_data[:limit]
|
|
161
115
|
|
|
116
|
+
longest_job_id = max(len(item[0]) for item in job_data)
|
|
117
|
+
spacing = longest_job_id + 5
|
|
162
118
|
try:
|
|
163
|
-
|
|
164
|
-
|
|
119
|
+
console = Console()
|
|
120
|
+
header_1 = "Job ID"
|
|
121
|
+
header_2 = "Submitted"
|
|
122
|
+
header_3 = "Status"
|
|
123
|
+
console.print(f"[bold]{header_1.ljust(spacing)}{header_2.ljust(36)}{header_3}[/bold]")
|
|
124
|
+
for job_id, submitted, status in job_data:
|
|
125
|
+
if status == "COMPLETED":
|
|
126
|
+
status_color = "green"
|
|
127
|
+
elif status in ["FAILED", "CANCELLED"]:
|
|
128
|
+
status_color = "red"
|
|
129
|
+
elif status in [
|
|
130
|
+
"INITIALIZING",
|
|
131
|
+
"INITIALIZED",
|
|
132
|
+
"CREATED",
|
|
133
|
+
"QUEUED",
|
|
134
|
+
"VALIDATING",
|
|
135
|
+
"RUNNING",
|
|
136
|
+
]:
|
|
137
|
+
status_color = "blue"
|
|
138
|
+
else:
|
|
139
|
+
status_color = "grey"
|
|
140
|
+
console.print(
|
|
141
|
+
f"{job_id.ljust(spacing)}{submitted.ljust(35)}",
|
|
142
|
+
f"[{status_color}]{status}[/{status_color}]",
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
console.print(f"\n{msg}", style="italic", justify="left")
|
|
146
|
+
|
|
147
|
+
except Exception: # pylint: disable=broad-exception-caught
|
|
165
148
|
handle_error(message="Failed to fetch quantum jobs.")
|
|
166
149
|
|
|
167
150
|
|
|
168
151
|
if __name__ == "__main__":
|
|
169
|
-
|
|
152
|
+
jobs_app()
|