qbraid-cli 0.8.0.dev1__py3-none-any.whl → 0.9.6__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 +93 -109
- 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.6.dist-info/LICENSE +41 -0
- qbraid_cli-0.9.6.dist-info/METADATA +179 -0
- qbraid_cli-0.9.6.dist-info/RECORD +42 -0
- {qbraid_cli-0.8.0.dev1.dist-info → qbraid_cli-0.9.6.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.6.dist-info}/entry_points.txt +0 -0
- {qbraid_cli-0.8.0.dev1.dist-info → qbraid_cli-0.9.6.dist-info}/top_level.txt +0 -0
qbraid_cli/jobs/toggle_braket.py
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
# Copyright (c) 2024, qBraid Development Team
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
|
|
1
4
|
"""
|
|
2
5
|
Module supporting 'qbraid jobs enable/disable braket' and commands.
|
|
3
6
|
|
|
@@ -5,11 +8,12 @@ Module supporting 'qbraid jobs enable/disable braket' and commands.
|
|
|
5
8
|
|
|
6
9
|
import logging
|
|
7
10
|
import os
|
|
11
|
+
import re
|
|
8
12
|
import subprocess
|
|
9
|
-
import sys
|
|
10
13
|
from pathlib import Path
|
|
11
|
-
from typing import Optional
|
|
14
|
+
from typing import Optional
|
|
12
15
|
|
|
16
|
+
import requests
|
|
13
17
|
import typer
|
|
14
18
|
|
|
15
19
|
from qbraid_cli.exceptions import QbraidException
|
|
@@ -19,46 +23,59 @@ logging.basicConfig(level=logging.INFO)
|
|
|
19
23
|
logger = logging.getLogger(__name__)
|
|
20
24
|
|
|
21
25
|
|
|
22
|
-
def
|
|
26
|
+
def fetch_botocore_version() -> Optional[str]:
|
|
27
|
+
"""Fetch the latest version of the botocore package from the qBraid GitHub repository."""
|
|
28
|
+
url = "https://raw.githubusercontent.com/qBraid/botocore/develop/botocore/__init__.py"
|
|
29
|
+
response = requests.get(url, timeout=5)
|
|
30
|
+
if response.status_code == 200:
|
|
31
|
+
content = response.text
|
|
32
|
+
version_match = re.search(r"__version__\s*=\s*['\"]([^'\"]+)['\"]", content)
|
|
33
|
+
if version_match:
|
|
34
|
+
return version_match.group(1)
|
|
35
|
+
return None
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def get_package_data(package: str) -> tuple[str, str, str, str]:
|
|
23
39
|
"""Retrieve package version and location data.
|
|
24
40
|
|
|
25
41
|
Args:
|
|
26
42
|
package (str): The name of the package to retrieve data for.
|
|
27
43
|
|
|
28
44
|
Returns:
|
|
29
|
-
|
|
30
|
-
|
|
45
|
+
tuple[str, str, str, str]: The installed and latest versions of the package, and the
|
|
46
|
+
local site-packages path where it is / would be installed.
|
|
31
47
|
|
|
32
48
|
Raises:
|
|
33
49
|
QbraidException: If package version or location data cannot be retrieved.
|
|
34
50
|
|
|
35
51
|
"""
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
from qbraid.exceptions import QbraidError
|
|
52
|
+
# pylint: disable=import-outside-toplevel
|
|
53
|
+
from qbraid_core.system.exceptions import QbraidSystemError
|
|
54
|
+
from qbraid_core.system.executables import get_active_python_path
|
|
55
|
+
from qbraid_core.system.packages import get_active_site_packages_path
|
|
56
|
+
from qbraid_core.system.versions import get_latest_package_version, get_local_package_version
|
|
42
57
|
|
|
43
58
|
try:
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
raise QbraidException("Failed to retrieve package version information") from err
|
|
59
|
+
python_pathlib = get_active_python_path()
|
|
60
|
+
site_packages_path = get_active_site_packages_path(python_path=python_pathlib)
|
|
61
|
+
installed_version = get_local_package_version(package, python_path=python_pathlib)
|
|
48
62
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
63
|
+
latest_version = None
|
|
64
|
+
if package in ["botocore", "boto3"]:
|
|
65
|
+
latest_version = fetch_botocore_version()
|
|
66
|
+
latest_version = latest_version or get_latest_package_version(package)
|
|
53
67
|
|
|
54
|
-
|
|
68
|
+
except QbraidSystemError as err:
|
|
69
|
+
raise QbraidException("Failed to retrieve required system and/or package metadata") from err
|
|
70
|
+
|
|
71
|
+
return installed_version, latest_version, str(site_packages_path), str(python_pathlib)
|
|
55
72
|
|
|
56
73
|
|
|
57
74
|
def confirm_updates(
|
|
58
75
|
mode: str,
|
|
59
76
|
site_packages_path: str,
|
|
60
77
|
installed_version: Optional[str] = None,
|
|
61
|
-
|
|
78
|
+
target_version: Optional[str] = None,
|
|
62
79
|
) -> None:
|
|
63
80
|
"""
|
|
64
81
|
Prompts the user to proceed with enabling or disabling qBraid Quantum Jobs.
|
|
@@ -68,10 +85,7 @@ def confirm_updates(
|
|
|
68
85
|
site_packages_path (str): The location of the site-packages directory where
|
|
69
86
|
target package(s) will be updated.
|
|
70
87
|
installed_version (optional, str): The installed version of the target package.
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
Returns:
|
|
74
|
-
None
|
|
88
|
+
target_version (optional, str): The latest version of the target package available on PyPI.
|
|
75
89
|
|
|
76
90
|
Raises:
|
|
77
91
|
ValueError: If an invalid mode is provided.
|
|
@@ -89,15 +103,15 @@ def confirm_updates(
|
|
|
89
103
|
else:
|
|
90
104
|
raise ValueError(f"Invalid mode: {mode}. Expected 'enable' or 'disable'.")
|
|
91
105
|
|
|
92
|
-
typer.echo(f"
|
|
106
|
+
typer.echo(f"==> WARNING: {provider}/{core_package} package required <==")
|
|
93
107
|
if (
|
|
94
108
|
installed_version is not None
|
|
95
|
-
and
|
|
96
|
-
and installed_version !=
|
|
109
|
+
and target_version is not None
|
|
110
|
+
and installed_version != target_version
|
|
97
111
|
):
|
|
98
|
-
typer.echo(f"==> WARNING: A
|
|
112
|
+
typer.echo(f"==> WARNING: A different version of {versioned_package} is required. <==")
|
|
99
113
|
typer.echo(f" current version: {installed_version}")
|
|
100
|
-
typer.echo(f"
|
|
114
|
+
typer.echo(f" target version: {target_version}")
|
|
101
115
|
|
|
102
116
|
gerund = mode[:-2].capitalize() + "ing"
|
|
103
117
|
|
|
@@ -117,81 +131,61 @@ def confirm_updates(
|
|
|
117
131
|
typer.echo("\nqBraidSystemExit: Exiting.")
|
|
118
132
|
raise typer.Exit()
|
|
119
133
|
|
|
120
|
-
typer.echo("")
|
|
121
|
-
|
|
122
134
|
|
|
123
135
|
def aws_configure_dummy() -> None:
|
|
124
136
|
"""
|
|
125
137
|
Initializes AWS configuration and credentials files with placeholder values.
|
|
126
138
|
|
|
127
|
-
This function ensures the existence of AWS config and credentials files in the user's home
|
|
128
|
-
directory. If these files do not already exist, it creates them and populates them with
|
|
129
|
-
placeholder values for the AWS access key and secret access key. While AWS credentials are not
|
|
130
|
-
required when submitting quantum tasks through qBraid, Amazon Braket requires these files to be
|
|
131
|
-
present to prevent configuration errors.
|
|
132
139
|
"""
|
|
133
|
-
|
|
134
|
-
config_path = aws_dir / "config"
|
|
135
|
-
credentials_path = aws_dir / "credentials"
|
|
136
|
-
|
|
137
|
-
def configure_aws():
|
|
138
|
-
aws_dir.mkdir(exist_ok=True)
|
|
139
|
-
if not config_path.exists():
|
|
140
|
-
config_content = "[default]\nregion = us-east-1\noutput = json\n"
|
|
141
|
-
config_path.write_text(config_content)
|
|
142
|
-
if not credentials_path.exists():
|
|
143
|
-
access_key, secret_key = "MYACCESSKEY", "MYSECRETKEY"
|
|
144
|
-
credentials_content = (
|
|
145
|
-
f"[default]\n"
|
|
146
|
-
f"aws_access_key_id = {access_key}\n"
|
|
147
|
-
f"aws_secret_access_key = {secret_key}\n"
|
|
148
|
-
)
|
|
149
|
-
credentials_path.write_text(credentials_content)
|
|
140
|
+
from qbraid_core.services.quantum.proxy_braket import aws_configure
|
|
150
141
|
|
|
151
142
|
try:
|
|
152
|
-
handle_filesystem_operation(
|
|
143
|
+
handle_filesystem_operation(aws_configure, Path.home() / ".aws")
|
|
153
144
|
except QbraidException:
|
|
154
145
|
handle_error(message="Failed to configure qBraid quantum jobs.")
|
|
155
146
|
|
|
156
147
|
|
|
157
|
-
def enable_braket():
|
|
148
|
+
def enable_braket(auto_confirm: bool = False):
|
|
158
149
|
"""Enable qBraid quantum jobs for Amazon Braket."""
|
|
159
|
-
|
|
150
|
+
installed, target, path, python_exe = run_progress_task(
|
|
160
151
|
get_package_data, "boto3", description="Solving environment..."
|
|
161
152
|
)
|
|
162
|
-
|
|
153
|
+
|
|
154
|
+
if not auto_confirm:
|
|
155
|
+
confirm_updates("enable", path, installed_version=installed, target_version=target)
|
|
156
|
+
typer.echo("")
|
|
157
|
+
|
|
163
158
|
aws_configure_dummy() # TODO: possibly add another confirmation for writing aws config files
|
|
164
159
|
|
|
165
160
|
try:
|
|
166
|
-
subprocess.check_call([
|
|
161
|
+
subprocess.check_call([python_exe, "-m", "pip", "install", f"boto3=={target}"])
|
|
162
|
+
subprocess.check_call([python_exe, "-m", "pip", "uninstall", "botocore", "-y", "--quiet"])
|
|
167
163
|
subprocess.check_call(
|
|
168
|
-
[
|
|
164
|
+
[python_exe, "-m", "pip", "install", "git+https://github.com/qBraid/botocore.git"]
|
|
169
165
|
)
|
|
170
|
-
|
|
171
|
-
[sys.executable, "-m", "pip", "install", "git+https://github.com/qBraid/botocore.git"]
|
|
172
|
-
)
|
|
173
|
-
except subprocess.CalledProcessError:
|
|
166
|
+
except (subprocess.CalledProcessError, FileNotFoundError):
|
|
174
167
|
handle_error(message="Failed to enable qBraid quantum jobs.")
|
|
175
168
|
|
|
176
169
|
typer.secho("\nSuccessfully enabled qBraid quantum jobs.", fg=typer.colors.GREEN, bold=True)
|
|
177
|
-
typer.secho(
|
|
178
|
-
"\nTo disable, run: `qbraid jobs disable braket`\n", fg=typer.colors.GREEN, bold=True
|
|
179
|
-
)
|
|
170
|
+
typer.secho("\nTo disable, run: \n\n\t$ qbraid jobs disable braket\n")
|
|
180
171
|
|
|
181
172
|
|
|
182
|
-
def disable_braket():
|
|
173
|
+
def disable_braket(auto_confirm: bool = False):
|
|
183
174
|
"""Disable qBraid quantum jobs for Amazon Braket."""
|
|
184
175
|
package = "botocore"
|
|
185
|
-
|
|
176
|
+
installed, latest, path, python_exe = run_progress_task(
|
|
186
177
|
get_package_data, package, description="Solving environment..."
|
|
187
178
|
)
|
|
188
|
-
package = f"{package}~={
|
|
189
|
-
|
|
179
|
+
package = f"{package}~={installed}" if installed < latest else package
|
|
180
|
+
|
|
181
|
+
if not auto_confirm:
|
|
182
|
+
confirm_updates("disable", path)
|
|
183
|
+
typer.echo("")
|
|
190
184
|
|
|
191
185
|
try:
|
|
192
186
|
subprocess.check_call(
|
|
193
187
|
[
|
|
194
|
-
|
|
188
|
+
python_exe,
|
|
195
189
|
"-m",
|
|
196
190
|
"pip",
|
|
197
191
|
"install",
|
|
@@ -200,8 +194,8 @@ def disable_braket():
|
|
|
200
194
|
],
|
|
201
195
|
stderr=subprocess.DEVNULL,
|
|
202
196
|
)
|
|
203
|
-
except subprocess.CalledProcessError:
|
|
197
|
+
except (subprocess.CalledProcessError, FileNotFoundError):
|
|
204
198
|
handle_error(message="Failed to disable qBraid quantum jobs.")
|
|
205
199
|
|
|
206
200
|
typer.secho("\nSuccessfully disabled qBraid quantum jobs.", fg=typer.colors.GREEN, bold=True)
|
|
207
|
-
typer.secho("\nTo enable, run:
|
|
201
|
+
typer.secho("\nTo enable, run: \n\n\t$ qbraid jobs enable braket\n")
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Copyright (c) 2024, qBraid Development Team
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
Module for validating command arguments for qBraid Quantum Jobs.
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import sys
|
|
10
|
+
from typing import Any, Callable, Optional
|
|
11
|
+
|
|
12
|
+
import typer
|
|
13
|
+
from rich.console import Console
|
|
14
|
+
|
|
15
|
+
from qbraid_cli.handlers import handle_error, run_progress_task, validate_item
|
|
16
|
+
|
|
17
|
+
LEGACY_ARGS: dict[str, str] = {
|
|
18
|
+
"amazon_braket": "braket",
|
|
19
|
+
"aws_braket": "braket",
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def validate_library(value: str) -> str:
|
|
24
|
+
"""Validate quantum jobs library."""
|
|
25
|
+
# pylint:disable-next=import-outside-toplevel
|
|
26
|
+
from qbraid_core.services.quantum.proxy import SUPPORTED_QJOB_LIBS
|
|
27
|
+
|
|
28
|
+
qjobs_libs = list(SUPPORTED_QJOB_LIBS.keys())
|
|
29
|
+
|
|
30
|
+
if value in LEGACY_ARGS:
|
|
31
|
+
old_value = value
|
|
32
|
+
value = LEGACY_ARGS[value]
|
|
33
|
+
|
|
34
|
+
console = Console()
|
|
35
|
+
console.print(
|
|
36
|
+
f"[red]DeprecationWarning:[/red] Argument '{old_value}' "
|
|
37
|
+
f"is deprecated. Use '{value}' instead.\n"
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
return validate_item(value, qjobs_libs, "Library")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def get_state(library: Optional[str] = None) -> tuple[str, dict[str, tuple[bool, bool]]]:
|
|
44
|
+
"""Get the state of qBraid Quantum Jobs for the specified library."""
|
|
45
|
+
from qbraid_core.services.quantum import QuantumClient
|
|
46
|
+
|
|
47
|
+
jobs_state = QuantumClient.qbraid_jobs_state(device_lib=library)
|
|
48
|
+
|
|
49
|
+
python_exe: str = jobs_state.get("exe", sys.executable)
|
|
50
|
+
libs_state: dict[str, Any] = jobs_state.get("libs", {})
|
|
51
|
+
|
|
52
|
+
state_values = {
|
|
53
|
+
lib: (state["supported"], state["enabled"]) for lib, state in libs_state.items()
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return python_exe, state_values
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def run_progress_get_state(
|
|
60
|
+
library: Optional[str] = None,
|
|
61
|
+
) -> tuple[str, dict[str, tuple[bool, bool]]]:
|
|
62
|
+
"""Run get state function with rich progress UI."""
|
|
63
|
+
return run_progress_task(
|
|
64
|
+
get_state,
|
|
65
|
+
library,
|
|
66
|
+
description="Collecting package metadata...",
|
|
67
|
+
error_message=f"Failed to collect {library} package metadata.",
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def handle_jobs_state(
|
|
72
|
+
library: str,
|
|
73
|
+
action: str, # 'enable' or 'disable'
|
|
74
|
+
action_callback: Callable[[], None],
|
|
75
|
+
) -> None:
|
|
76
|
+
"""Handle the common logic for enabling or disabling qBraid Quantum Jobs."""
|
|
77
|
+
_, state_values = run_progress_get_state(library)
|
|
78
|
+
installed, enabled = state_values[library]
|
|
79
|
+
|
|
80
|
+
if not installed:
|
|
81
|
+
handle_error(
|
|
82
|
+
message=f"{library} not installed."
|
|
83
|
+
) # TODO: Provide command to install library?
|
|
84
|
+
if (enabled and action == "enable") or (not enabled and action == "disable"):
|
|
85
|
+
action_color = "green" if enabled else "red"
|
|
86
|
+
console = Console()
|
|
87
|
+
console.print(
|
|
88
|
+
f"\nqBraid quantum jobs already [bold {action_color}]{action}d[/bold {action_color}] "
|
|
89
|
+
f"for [magenta]{library}[/magenta].\n\nCheck the state of all quantum jobs "
|
|
90
|
+
"libraries in this environment with: \n\n\t$ qbraid jobs state\n"
|
|
91
|
+
)
|
|
92
|
+
raise typer.Exit()
|
|
93
|
+
|
|
94
|
+
action_callback() # Perform the specific enable/disable action
|
qbraid_cli/kernels/__init__.py
CHANGED
qbraid_cli/kernels/app.py
CHANGED
|
@@ -1,42 +1,99 @@
|
|
|
1
|
+
# Copyright (c) 2024, qBraid Development Team
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
|
|
1
4
|
"""
|
|
2
|
-
Module defining commands in the 'qbraid
|
|
5
|
+
Module defining commands in the 'qbraid kernels' namespace.
|
|
3
6
|
|
|
4
7
|
"""
|
|
5
8
|
|
|
6
9
|
import typer
|
|
10
|
+
from rich.console import Console
|
|
11
|
+
|
|
12
|
+
from qbraid_cli.handlers import handle_error
|
|
7
13
|
|
|
8
|
-
|
|
14
|
+
kernels_app = typer.Typer(help="Manage qBraid kernels.", no_args_is_help=True)
|
|
9
15
|
|
|
10
16
|
|
|
11
|
-
@
|
|
17
|
+
@kernels_app.command(name="list")
|
|
12
18
|
def kernels_list():
|
|
13
19
|
"""List all available kernels."""
|
|
14
|
-
from
|
|
20
|
+
from qbraid_core.services.environments.kernels import get_all_kernels
|
|
15
21
|
|
|
16
|
-
|
|
17
|
-
|
|
22
|
+
console = Console()
|
|
23
|
+
# Get the list of kernelspecs
|
|
24
|
+
kernelspecs: dict = get_all_kernels()
|
|
18
25
|
|
|
19
26
|
if len(kernelspecs) == 0:
|
|
20
|
-
print("No qBraid kernels active.")
|
|
21
|
-
|
|
27
|
+
console.print("No qBraid kernels are active.")
|
|
28
|
+
console.print("\nUse 'qbraid kernels add' to add a new kernel.")
|
|
22
29
|
return
|
|
23
30
|
|
|
24
31
|
longest_kernel_name = max(len(kernel_name) for kernel_name in kernelspecs)
|
|
25
32
|
spacing = longest_kernel_name + 10
|
|
26
33
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
34
|
+
output_lines = []
|
|
35
|
+
output_lines.append("# qbraid kernels:")
|
|
36
|
+
output_lines.append("#")
|
|
37
|
+
output_lines.append("")
|
|
30
38
|
|
|
31
39
|
# Ensure 'python3' kernel is printed first if it exists
|
|
32
|
-
|
|
40
|
+
default_kernel_name = "python3"
|
|
41
|
+
python3_kernel_info = kernelspecs.pop(default_kernel_name, None)
|
|
33
42
|
if python3_kernel_info:
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
#
|
|
43
|
+
line = f"{default_kernel_name.ljust(spacing)}{python3_kernel_info['resource_dir']}"
|
|
44
|
+
output_lines.append(line)
|
|
45
|
+
# print rest of the kernels
|
|
37
46
|
for kernel_name, kernel_info in sorted(kernelspecs.items()):
|
|
38
|
-
|
|
47
|
+
line = f"{kernel_name.ljust(spacing)}{kernel_info['resource_dir']}"
|
|
48
|
+
output_lines.append(line)
|
|
49
|
+
|
|
50
|
+
final_output = "\n".join(output_lines)
|
|
51
|
+
|
|
52
|
+
console.print(final_output)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@kernels_app.command(name="add")
|
|
56
|
+
def kernels_add(
|
|
57
|
+
environment: str = typer.Argument(
|
|
58
|
+
..., help="Name of environment for which to add ipykernel. Values from 'qbraid envs list'."
|
|
59
|
+
),
|
|
60
|
+
):
|
|
61
|
+
"""Add a kernel."""
|
|
62
|
+
from qbraid_core.services.environments.kernels import add_kernels
|
|
63
|
+
|
|
64
|
+
try:
|
|
65
|
+
add_kernels(environment)
|
|
66
|
+
except ValueError:
|
|
67
|
+
handle_error(
|
|
68
|
+
message="Failed to add kernel(s). Please verify that the environment exists.",
|
|
69
|
+
include_traceback=True,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
console = Console()
|
|
73
|
+
console.print(f"\nSuccessfully added '{environment}' kernel(s).", highlight=False)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@kernels_app.command(name="remove")
|
|
77
|
+
def kernels_remove(
|
|
78
|
+
environment: str = typer.Argument(
|
|
79
|
+
...,
|
|
80
|
+
help=("Name of environment for which to remove ipykernel. Values from 'qbraid envs list'."),
|
|
81
|
+
),
|
|
82
|
+
):
|
|
83
|
+
"""Remove a kernel."""
|
|
84
|
+
from qbraid_core.services.environments.kernels import remove_kernels
|
|
85
|
+
|
|
86
|
+
try:
|
|
87
|
+
remove_kernels(environment)
|
|
88
|
+
except ValueError:
|
|
89
|
+
handle_error(
|
|
90
|
+
message="Failed to remove kernel(s). Please verify that the environment exists.",
|
|
91
|
+
include_traceback=True,
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
console = Console()
|
|
95
|
+
console.print(f"\nSuccessfully removed '{environment}' kernel(s).", highlight=False)
|
|
39
96
|
|
|
40
97
|
|
|
41
98
|
if __name__ == "__main__":
|
|
42
|
-
|
|
99
|
+
kernels_app()
|
qbraid_cli/main.py
CHANGED
|
@@ -1,33 +1,55 @@
|
|
|
1
|
+
# Copyright (c) 2024, qBraid Development Team
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
|
|
1
4
|
"""
|
|
2
5
|
Entrypoint for the qBraid CLI.
|
|
3
6
|
|
|
4
7
|
"""
|
|
5
8
|
|
|
9
|
+
import click
|
|
10
|
+
import rich
|
|
6
11
|
import typer
|
|
7
12
|
|
|
8
|
-
from .
|
|
9
|
-
from .
|
|
10
|
-
from .
|
|
11
|
-
from .
|
|
12
|
-
from .
|
|
13
|
-
from .
|
|
13
|
+
from qbraid_cli.account import account_app
|
|
14
|
+
from qbraid_cli.admin import admin_app
|
|
15
|
+
from qbraid_cli.chat import ChatFormat, list_models_callback, prompt_callback
|
|
16
|
+
from qbraid_cli.configure import configure_app
|
|
17
|
+
from qbraid_cli.devices import devices_app
|
|
18
|
+
from qbraid_cli.files import files_app
|
|
19
|
+
from qbraid_cli.jobs import jobs_app
|
|
20
|
+
|
|
21
|
+
try:
|
|
22
|
+
from qbraid_cli.envs import envs_app
|
|
23
|
+
from qbraid_cli.kernels import kernels_app
|
|
24
|
+
from qbraid_cli.pip import pip_app
|
|
25
|
+
|
|
26
|
+
ENVS_COMMANDS = True
|
|
27
|
+
except ImportError:
|
|
28
|
+
ENVS_COMMANDS = False
|
|
29
|
+
|
|
30
|
+
app = typer.Typer(context_settings={"help_option_names": ["-h", "--help"]})
|
|
14
31
|
|
|
15
|
-
app =
|
|
32
|
+
app.add_typer(admin_app, name="admin")
|
|
16
33
|
app.add_typer(configure_app, name="configure")
|
|
17
|
-
app.add_typer(
|
|
18
|
-
app.add_typer(jobs_app, name="jobs")
|
|
34
|
+
app.add_typer(account_app, name="account")
|
|
19
35
|
app.add_typer(devices_app, name="devices")
|
|
20
|
-
app.add_typer(
|
|
21
|
-
app.add_typer(
|
|
36
|
+
app.add_typer(files_app, name="files")
|
|
37
|
+
app.add_typer(jobs_app, name="jobs")
|
|
38
|
+
|
|
39
|
+
if ENVS_COMMANDS is True:
|
|
40
|
+
app.add_typer(envs_app, name="envs")
|
|
41
|
+
app.add_typer(kernels_app, name="kernels")
|
|
42
|
+
app.add_typer(pip_app, name="pip")
|
|
22
43
|
|
|
23
44
|
|
|
24
45
|
def version_callback(value: bool):
|
|
25
46
|
"""Show the version and exit."""
|
|
26
47
|
if value:
|
|
27
|
-
|
|
48
|
+
# pylint: disable-next=import-error
|
|
49
|
+
from ._version import __version__ # type: ignore
|
|
28
50
|
|
|
29
51
|
typer.echo(f"qbraid-cli/{__version__}")
|
|
30
|
-
raise typer.Exit()
|
|
52
|
+
raise typer.Exit(0)
|
|
31
53
|
|
|
32
54
|
|
|
33
55
|
def show_banner():
|
|
@@ -50,7 +72,7 @@ def show_banner():
|
|
|
50
72
|
typer.echo("")
|
|
51
73
|
typer.echo("- Use 'qbraid --version' to see the current version.")
|
|
52
74
|
typer.echo("")
|
|
53
|
-
|
|
75
|
+
rich.print("Reference Docs: https://docs.qbraid.com/cli/api-reference/qbraid")
|
|
54
76
|
|
|
55
77
|
|
|
56
78
|
@app.callback(invoke_without_command=True)
|
|
@@ -59,6 +81,7 @@ def main(
|
|
|
59
81
|
version: bool = typer.Option(
|
|
60
82
|
None,
|
|
61
83
|
"--version",
|
|
84
|
+
"-v",
|
|
62
85
|
callback=version_callback,
|
|
63
86
|
is_eager=True,
|
|
64
87
|
help="Show the version and exit.",
|
|
@@ -69,5 +92,34 @@ def main(
|
|
|
69
92
|
show_banner()
|
|
70
93
|
|
|
71
94
|
|
|
95
|
+
@app.command(help="Interact with qBraid AI chat service.", no_args_is_help=True)
|
|
96
|
+
def chat(
|
|
97
|
+
prompt: str = typer.Option(
|
|
98
|
+
None, "--prompt", "-p", help="The prompt to send to the chat service."
|
|
99
|
+
),
|
|
100
|
+
model: str = typer.Option(None, "--model", "-m", help="The model to use for the chat service."),
|
|
101
|
+
response_format: ChatFormat = typer.Option(
|
|
102
|
+
ChatFormat.text, "--format", "-f", help="The format of the response."
|
|
103
|
+
),
|
|
104
|
+
stream: bool = typer.Option(False, "--stream", "-s", help="Stream the response."),
|
|
105
|
+
list_models: bool = typer.Option(
|
|
106
|
+
False, "--list-models", "-l", help="List available chat models."
|
|
107
|
+
),
|
|
108
|
+
):
|
|
109
|
+
"""
|
|
110
|
+
Interact with qBraid AI chat service.
|
|
111
|
+
|
|
112
|
+
"""
|
|
113
|
+
if list_models:
|
|
114
|
+
list_models_callback()
|
|
115
|
+
elif prompt:
|
|
116
|
+
prompt_callback(prompt, model, response_format, stream)
|
|
117
|
+
else:
|
|
118
|
+
raise click.UsageError(
|
|
119
|
+
"Invalid command. Please provide a prompt using --prompt "
|
|
120
|
+
"or use --list-models to view available models."
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
|
|
72
124
|
if __name__ == "__main__":
|
|
73
125
|
app()
|
qbraid_cli/pip/app.py
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Copyright (c) 2024, qBraid Development Team
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
Module defining commands in the 'qbraid pip' namespace.
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import subprocess
|
|
10
|
+
import sys
|
|
11
|
+
|
|
12
|
+
import typer
|
|
13
|
+
from qbraid_core.system.exceptions import QbraidSystemError
|
|
14
|
+
from qbraid_core.system.executables import get_active_python_path
|
|
15
|
+
|
|
16
|
+
from qbraid_cli.handlers import handle_error
|
|
17
|
+
from qbraid_cli.pip.hooks import get_env_cfg_path, safe_set_include_sys_packages
|
|
18
|
+
|
|
19
|
+
pip_app = typer.Typer(help="Run pip command in active qBraid environment.", no_args_is_help=True)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@pip_app.command(
|
|
23
|
+
"install", context_settings={"allow_extra_args": True, "ignore_unknown_options": True}
|
|
24
|
+
)
|
|
25
|
+
def pip_install(ctx: typer.Context):
|
|
26
|
+
"""
|
|
27
|
+
Perform pip install action with open-ended arguments and options.
|
|
28
|
+
|
|
29
|
+
"""
|
|
30
|
+
try:
|
|
31
|
+
python_exe = get_active_python_path()
|
|
32
|
+
cfg_path = get_env_cfg_path(python_exe)
|
|
33
|
+
except QbraidSystemError:
|
|
34
|
+
python_exe = sys.executable
|
|
35
|
+
cfg_path = None
|
|
36
|
+
|
|
37
|
+
safe_set_include_sys_packages(False, cfg_path)
|
|
38
|
+
|
|
39
|
+
command = [str(python_exe), "-m", "pip", "install"] + ctx.args
|
|
40
|
+
|
|
41
|
+
try:
|
|
42
|
+
subprocess.check_call(command)
|
|
43
|
+
except (subprocess.CalledProcessError, FileNotFoundError):
|
|
44
|
+
handle_error(message="Failed carry-out pip command.")
|
|
45
|
+
finally:
|
|
46
|
+
safe_set_include_sys_packages(True, cfg_path)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
if __name__ == "__main__":
|
|
50
|
+
pip_app()
|