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.

Files changed (45) hide show
  1. qbraid_cli/_version.py +2 -2
  2. qbraid_cli/account/__init__.py +11 -0
  3. qbraid_cli/account/app.py +65 -0
  4. qbraid_cli/admin/__init__.py +11 -0
  5. qbraid_cli/admin/app.py +59 -0
  6. qbraid_cli/admin/headers.py +235 -0
  7. qbraid_cli/admin/validation.py +32 -0
  8. qbraid_cli/chat/__init__.py +11 -0
  9. qbraid_cli/chat/app.py +76 -0
  10. qbraid_cli/configure/__init__.py +6 -1
  11. qbraid_cli/configure/actions.py +111 -0
  12. qbraid_cli/configure/app.py +93 -109
  13. qbraid_cli/devices/__init__.py +6 -1
  14. qbraid_cli/devices/app.py +43 -35
  15. qbraid_cli/devices/validation.py +26 -0
  16. qbraid_cli/envs/__init__.py +6 -1
  17. qbraid_cli/envs/activate.py +8 -5
  18. qbraid_cli/envs/app.py +116 -197
  19. qbraid_cli/envs/create.py +13 -109
  20. qbraid_cli/envs/data_handling.py +46 -0
  21. qbraid_cli/exceptions.py +3 -0
  22. qbraid_cli/files/__init__.py +11 -0
  23. qbraid_cli/files/app.py +118 -0
  24. qbraid_cli/handlers.py +46 -12
  25. qbraid_cli/jobs/__init__.py +6 -1
  26. qbraid_cli/jobs/app.py +76 -93
  27. qbraid_cli/jobs/toggle_braket.py +68 -74
  28. qbraid_cli/jobs/validation.py +94 -0
  29. qbraid_cli/kernels/__init__.py +6 -1
  30. qbraid_cli/kernels/app.py +74 -17
  31. qbraid_cli/main.py +66 -14
  32. qbraid_cli/pip/__init__.py +11 -0
  33. qbraid_cli/pip/app.py +50 -0
  34. qbraid_cli/pip/hooks.py +74 -0
  35. qbraid_cli/py.typed +0 -0
  36. qbraid_cli-0.9.6.dist-info/LICENSE +41 -0
  37. qbraid_cli-0.9.6.dist-info/METADATA +179 -0
  38. qbraid_cli-0.9.6.dist-info/RECORD +42 -0
  39. {qbraid_cli-0.8.0.dev1.dist-info → qbraid_cli-0.9.6.dist-info}/WHEEL +1 -1
  40. qbraid_cli/credits/__init__.py +0 -6
  41. qbraid_cli/credits/app.py +0 -30
  42. qbraid_cli-0.8.0.dev1.dist-info/METADATA +0 -136
  43. qbraid_cli-0.8.0.dev1.dist-info/RECORD +0 -25
  44. {qbraid_cli-0.8.0.dev1.dist-info → qbraid_cli-0.9.6.dist-info}/entry_points.txt +0 -0
  45. {qbraid_cli-0.8.0.dev1.dist-info → qbraid_cli-0.9.6.dist-info}/top_level.txt +0 -0
@@ -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, Tuple
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 get_package_data(package: str) -> Tuple[str, str, str]:
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
- Tuple[str, str, str]: The installed and latest versions of the package, and the
30
- local site-packages path where it is / would be installed.
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
- from qbraid.api.system import (
37
- get_active_site_packages_path,
38
- get_latest_package_version,
39
- get_local_package_version,
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
- installed_version = get_local_package_version(package)
45
- latest_version = get_latest_package_version(package)
46
- except QbraidError as err:
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
- try:
50
- site_packages_path = get_active_site_packages_path()
51
- except QbraidError as err:
52
- raise QbraidException("Failed to retrieve site-package location") from err
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
- return installed_version, latest_version, site_packages_path
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
- latest_version: Optional[str] = None,
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
- latest_version (optional, str): The latest version of the target package available on PyPI.
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"\n==> WARNING: {provider}/{core_package} package required <==")
106
+ typer.echo(f"==> WARNING: {provider}/{core_package} package required <==")
93
107
  if (
94
108
  installed_version is not None
95
- and latest_version is not None
96
- and installed_version != latest_version
109
+ and target_version is not None
110
+ and installed_version != target_version
97
111
  ):
98
- typer.echo(f"==> WARNING: A newer version of {versioned_package} exists. <==")
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" latest version: {latest_version}")
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
- aws_dir = Path.home() / ".aws"
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(configure_aws, aws_dir)
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
- installed_version, latest_version, site_packages_path = run_progress_task(
150
+ installed, target, path, python_exe = run_progress_task(
160
151
  get_package_data, "boto3", description="Solving environment..."
161
152
  )
162
- confirm_updates("enable", site_packages_path, installed_version, latest_version)
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([sys.executable, "-m", "pip", "install", "--upgrade", "boto3"])
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
- [sys.executable, "-m", "pip", "uninstall", "botocore", "-y", "--quiet"]
164
+ [python_exe, "-m", "pip", "install", "git+https://github.com/qBraid/botocore.git"]
169
165
  )
170
- subprocess.check_call(
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
- installed_version, latest_version, site_packages_path = run_progress_task(
176
+ installed, latest, path, python_exe = run_progress_task(
186
177
  get_package_data, package, description="Solving environment..."
187
178
  )
188
- package = f"{package}~={installed_version}" if installed_version < latest_version else package
189
- confirm_updates("disable", site_packages_path)
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
- sys.executable,
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: `qbraid jobs enable braket`\n", fg=typer.colors.GREEN, bold=True)
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
@@ -1,6 +1,11 @@
1
+ # Copyright (c) 2024, qBraid Development Team
2
+ # All rights reserved.
3
+
1
4
  """
2
5
  Module defining the qbraid kernels namespace
3
6
 
4
7
  """
5
8
 
6
- from .app import app
9
+ from .app import kernels_app
10
+
11
+ __all__ = ["kernels_app"]
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 jobs' namespace.
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
- app = typer.Typer(help="Manage qBraid kernels.")
14
+ kernels_app = typer.Typer(help="Manage qBraid kernels.", no_args_is_help=True)
9
15
 
10
16
 
11
- @app.command(name="list")
17
+ @kernels_app.command(name="list")
12
18
  def kernels_list():
13
19
  """List all available kernels."""
14
- from jupyter_client.kernelspec import KernelSpecManager
20
+ from qbraid_core.services.environments.kernels import get_all_kernels
15
21
 
16
- kernel_spec_manager = KernelSpecManager()
17
- kernelspecs = kernel_spec_manager.get_all_specs()
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
- # print("\nUse 'qbraid kernels add' to add a new kernel.")
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
- print("# qbraid kernels:")
28
- print("#")
29
- print("")
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
- python3_kernel_info = kernelspecs.pop("python3", None)
40
+ default_kernel_name = "python3"
41
+ python3_kernel_info = kernelspecs.pop(default_kernel_name, None)
33
42
  if python3_kernel_info:
34
- print("python3".ljust(spacing) + python3_kernel_info["resource_dir"])
35
-
36
- # Print the rest of the kernels
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
- print(f"{kernel_name.ljust(spacing)}{kernel_info['resource_dir']}")
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
- app()
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 .configure import app as configure_app
9
- from .credits import app as credits_app
10
- from .devices import app as devices_app
11
- from .envs import app as envs_app
12
- from .jobs import app as jobs_app
13
- from .kernels import app as kernels_app
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 = typer.Typer()
32
+ app.add_typer(admin_app, name="admin")
16
33
  app.add_typer(configure_app, name="configure")
17
- app.add_typer(envs_app, name="envs")
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(kernels_app, name="kernels")
21
- app.add_typer(credits_app, name="credits")
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
- from ._version import __version__
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
- typer.echo("Reference Docs: https://docs.qbraid.com/projects/cli/en/latest/cli/qbraid.html")
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()
@@ -0,0 +1,11 @@
1
+ # Copyright (c) 2024, qBraid Development Team
2
+ # All rights reserved.
3
+
4
+ """
5
+ Module defining the qbraid pip namespace
6
+
7
+ """
8
+
9
+ from .app import pip_app
10
+
11
+ __all__ = ["pip_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()