qbraid-cli 0.8.0.dev3__py3-none-any.whl → 0.8.0.dev5__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 CHANGED
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '0.8.0.dev3'
16
- __version_tuple__ = version_tuple = (0, 8, 0, 'dev3')
15
+ __version__ = version = '0.8.0.dev5'
16
+ __version_tuple__ = version_tuple = (0, 8, 0, 'dev5')
@@ -0,0 +1,9 @@
1
+ # Copyright (c) 2024, qBraid Development Team
2
+ # All rights reserved.
3
+
4
+ """
5
+ Module defining the qbraid admin namespace
6
+
7
+ """
8
+
9
+ from .app import admin_app
@@ -0,0 +1,50 @@
1
+ # Copyright (c) 2024, qBraid Development Team
2
+ # All rights reserved.
3
+
4
+ """
5
+ Module defining commands in the 'qbraid admin' namespace.
6
+
7
+ """
8
+
9
+ from typing import List
10
+
11
+ import typer
12
+
13
+ from qbraid_cli.admin.headers import check_and_fix_headers
14
+ from qbraid_cli.admin.validation import validate_header_type, validate_paths_exist
15
+
16
+ # disable pretty_exceptions_show_locals to avoid printing sensative information in the traceback
17
+ admin_app = typer.Typer(
18
+ help="CI/CD commands for qBraid maintainers.",
19
+ pretty_exceptions_show_locals=False,
20
+ )
21
+
22
+
23
+ @admin_app.command(name="headers")
24
+ def admin_headers(
25
+ src_paths: List[str] = typer.Argument(
26
+ ..., help="Source file or directory paths to verify.", callback=validate_paths_exist
27
+ ),
28
+ header_type: str = typer.Option(
29
+ "default",
30
+ "--type",
31
+ "-t",
32
+ help="Type of header to use ('default' or 'gpl').",
33
+ callback=validate_header_type,
34
+ ),
35
+ skip_files: List[str] = typer.Option(
36
+ [], "--skip", "-s", help="Files to skip during verification.", callback=validate_paths_exist
37
+ ),
38
+ fix: bool = typer.Option(
39
+ False, "--fix", "-f", help="Whether to fix the headers instead of just verifying."
40
+ ),
41
+ ):
42
+ """
43
+ Verifies and optionally fixes qBraid headers in specified files and directories.
44
+
45
+ """
46
+ check_and_fix_headers(src_paths, header_type=header_type, skip_files=skip_files, fix=fix)
47
+
48
+
49
+ if __name__ == "__main__":
50
+ admin_app()
@@ -0,0 +1,193 @@
1
+ # Copyright (c) 2024, qBraid Development Team
2
+ # All rights reserved.
3
+
4
+ """
5
+ Script to verify qBraid copyright file headers
6
+
7
+ """
8
+ import os
9
+ import sys
10
+ from typing import List, Optional
11
+
12
+ from rich.console import Console
13
+
14
+ # pylint: disable=too-many-branches,too-many-statements
15
+
16
+ DEFAULT_HEADER = """# Copyright (c) 2024, qBraid Development Team
17
+ # All rights reserved.
18
+ """
19
+
20
+ DEFAULT_HEADER_GPL = """# Copyright (C) 2024 qBraid
21
+ #
22
+ # This file is part of the qBraid-SDK
23
+ #
24
+ # The qBraid-SDK is free software released under the GNU General Public License v3
25
+ # or later. You can redistribute and/or modify it under the terms of the GPL v3.
26
+ # See the LICENSE file in the project root or <https://www.gnu.org/licenses/gpl-3.0.html>.
27
+ #
28
+ # THERE IS NO WARRANTY for the qBraid-SDK, as per Section 15 of the GPL v3.
29
+ """
30
+
31
+ HEADER_TYPES = {
32
+ "default": DEFAULT_HEADER,
33
+ "gpl": DEFAULT_HEADER_GPL,
34
+ }
35
+
36
+
37
+ def check_and_fix_headers(
38
+ src_paths: List[str],
39
+ header_type: str = "default",
40
+ skip_files: Optional[List[str]] = None,
41
+ fix: bool = False,
42
+ ) -> None:
43
+ """Script to add or verify qBraid copyright file headers"""
44
+ try:
45
+ header = HEADER_TYPES[header_type]
46
+ except KeyError as err:
47
+ raise ValueError(
48
+ f"Invalid header type: {HEADER_TYPES}. Expected one of {list(HEADER_TYPES.keys())}"
49
+ ) from err
50
+
51
+ for path in src_paths:
52
+ if not os.path.exists(path):
53
+ sys.stderr.write(
54
+ f"Usage: qbraid verify_headers [OPTIONS] SRC ...\n"
55
+ f"Try 'qbraid verify_headers --help' for help.\n\n"
56
+ f"Error: Invalid value for 'SRC ...': Path '{path}' does not exist.\n"
57
+ )
58
+ sys.exit(1)
59
+
60
+ header_2023 = header.replace("2024", "2023")
61
+
62
+ skip_files = skip_files or []
63
+
64
+ failed_headers = []
65
+ fixed_headers = []
66
+
67
+ console = Console()
68
+
69
+ def should_skip(file_path: str, content: str) -> bool:
70
+ if file_path in skip_files:
71
+ return True
72
+
73
+ if os.path.basename(file_path) == "__init__.py":
74
+ return not content.strip()
75
+
76
+ skip_header_tag = "# qbraid: skip-header"
77
+ line_number = 0
78
+
79
+ for line in content.splitlines():
80
+ line_number += 1
81
+ if 5 <= line_number <= 30 and skip_header_tag in line:
82
+ return True
83
+ if line_number > 30:
84
+ break
85
+
86
+ return False
87
+
88
+ def replace_or_add_header(file_path: str, fix: bool = False) -> None:
89
+ with open(file_path, "r", encoding="ISO-8859-1") as f:
90
+ content = f.read()
91
+
92
+ # This finds the start of the actual content after skipping initial whitespace and comments.
93
+ lines = content.splitlines()
94
+ first_non_comment_line_index = next(
95
+ (i for i, line in enumerate(lines) if not line.strip().startswith("#")), None
96
+ )
97
+
98
+ # Prepare the content by stripping leading and trailing whitespace and separating into lines
99
+ actual_content = (
100
+ "\n".join(lines[first_non_comment_line_index:]).strip()
101
+ if first_non_comment_line_index is not None
102
+ else ""
103
+ )
104
+
105
+ # Check if the content already starts with the header or if the file should be skipped
106
+ if (
107
+ content.lstrip().startswith(header)
108
+ or content.lstrip().startswith(header_2023)
109
+ or should_skip(file_path, content)
110
+ ):
111
+ return
112
+
113
+ if not fix:
114
+ failed_headers.append(file_path)
115
+ else:
116
+ # Form the new content by combining the header, one blank line, and the actual content
117
+ new_content = header.strip() + "\n\n" + actual_content
118
+ with open(file_path, "w", encoding="ISO-8859-1") as f:
119
+ f.write(new_content)
120
+ fixed_headers.append(file_path)
121
+
122
+ def process_files_in_directory(directory: str, fix: bool = False) -> int:
123
+ count = 0
124
+ if not os.path.isdir(directory):
125
+ return count
126
+ for root, _, files in os.walk(directory):
127
+ for file in files:
128
+ if file.endswith(".py"):
129
+ file_path = os.path.join(root, file)
130
+ replace_or_add_header(file_path, fix)
131
+ count += 1
132
+ return count
133
+
134
+ checked = 0
135
+ for item in src_paths:
136
+ if os.path.isdir(item):
137
+ checked += process_files_in_directory(item, fix)
138
+ elif os.path.isfile(item) and item.endswith(".py"):
139
+ replace_or_add_header(item, fix)
140
+ checked += 1
141
+ else:
142
+ failed_headers.append(item)
143
+ print(f"File or directory not found: {item}")
144
+
145
+ if not fix:
146
+ if failed_headers:
147
+ for file in failed_headers:
148
+ console.print(f"[bold]would fix {file}[/bold]")
149
+ num_failed = len(failed_headers)
150
+ num_passed = checked - num_failed
151
+ s1, s2 = ("", "s") if num_failed == 1 else ("s", "")
152
+ s_passed = "" if num_passed == 1 else "s"
153
+ console.print("[bold]\nOh no![/bold] 💥 💔 💥")
154
+ if num_passed > 0:
155
+ punc = ", "
156
+ passed_msg = f"[blue]{num_passed}[/blue] file{s_passed} would be left unchanged."
157
+ else:
158
+ punc = "."
159
+ passed_msg = ""
160
+
161
+ failed_msg = f"[bold][blue]{num_failed}[/blue] file{s1} need{s2} updating{punc}[/bold]"
162
+ console.print(f"{failed_msg}{passed_msg}")
163
+ elif checked == 0:
164
+ console.print("[bold]No Python files present. Nothing to do[/bold] 😴")
165
+ else:
166
+ s_checked = "" if checked == 1 else "s"
167
+ console.print("[bold]All done![/bold] ✨ 🚀 ✨")
168
+ console.print(f"[blue]{checked}[/blue] file{s_checked} would be left unchanged.")
169
+
170
+ else:
171
+ for file in fixed_headers:
172
+ console.print(f"[bold]fixed {file}[/bold]")
173
+ num_fixed = len(fixed_headers)
174
+ num_ok = checked - num_fixed
175
+ s_fixed = "" if num_fixed == 1 else "s"
176
+ s_ok = "" if num_ok == 1 else "s"
177
+ console.print("\n[bold]All done![/bold] ✨ 🚀 ✨")
178
+ if num_ok > 0:
179
+ punc = ", "
180
+ unchanged_msg = f"[blue]{num_ok}[/blue] file{s_ok} left unchanged."
181
+ else:
182
+ punc = "."
183
+ unchanged_msg = ""
184
+
185
+ if num_fixed > 0:
186
+ fixed_msg = f"[bold][blue]{num_fixed}[/blue] file{s_fixed} fixed{punc}[/bold]"
187
+ else:
188
+ fixed_msg = ""
189
+
190
+ if fixed_msg or unchanged_msg:
191
+ console.print(f"{fixed_msg}{unchanged_msg}")
192
+ else:
193
+ console.print("[bold]No Python files present. Nothing to do[/bold] 😴")
@@ -0,0 +1,33 @@
1
+ # Copyright (c) 2024, qBraid Development Team
2
+ # All rights reserved.
3
+
4
+ """
5
+ Module for validating command arguments for qBraid admin commands.
6
+
7
+ """
8
+
9
+ import os
10
+ from typing import List
11
+
12
+ import typer
13
+
14
+ from qbraid_cli.admin.headers import HEADER_TYPES
15
+ from qbraid_cli.handlers import _format_list_items, validate_item
16
+
17
+
18
+ def validate_header_type(value: str) -> str:
19
+ """Validate header type."""
20
+ header_types = list(HEADER_TYPES.keys())
21
+ return validate_item(value, header_types, "Header type")
22
+
23
+
24
+ def validate_paths_exist(paths: List[str]) -> List[str]:
25
+ """Verifies that each path in the provided list exists."""
26
+ non_existent_paths = [path for path in paths if not os.path.exists(path)]
27
+ if non_existent_paths:
28
+ if len(non_existent_paths) == 1:
29
+ raise typer.BadParameter(f"Path '{non_existent_paths[0]}' does not exist")
30
+ raise typer.BadParameter(
31
+ f"The following paths do not exist: {_format_list_items(non_existent_paths)}"
32
+ )
33
+ return paths
@@ -4,7 +4,6 @@
4
4
  """
5
5
  Module for validating command arguments for qBraid devices commands.
6
6
 
7
-
8
7
  """
9
8
 
10
9
  from typing import Optional, Union
qbraid_cli/handlers.py CHANGED
@@ -44,7 +44,11 @@ def handle_error(
44
44
  full_message = f"\n{error_prefix} {message}\n"
45
45
  if include_traceback:
46
46
  tb_string = traceback.format_exc()
47
- full_message += f"\n{tb_string}"
47
+ # TODO: find out reason for weird traceback emitted from
48
+ # qbraid jobs enable/disable when library not installed.
49
+ # For now, if matches, just don't print it.
50
+ if tb_string.strip() != "NoneType: None":
51
+ full_message += f"\n{tb_string}"
48
52
  typer.echo(full_message, err=True)
49
53
  raise typer.Exit(code=1)
50
54
 
qbraid_cli/jobs/app.py CHANGED
@@ -5,8 +5,6 @@
5
5
  Module defining commands in the 'qbraid jobs' namespace.
6
6
 
7
7
  """
8
-
9
- import sys
10
8
  from typing import Any, Callable, Dict, Tuple
11
9
 
12
10
  import typer
@@ -68,7 +66,8 @@ def jobs_state(
68
66
  )
69
67
  ) -> None:
70
68
  """Display the state of qBraid Quantum Jobs for the current environment."""
71
- state_values: Dict[str, Tuple[bool, bool]] = run_progress_get_state(library)
69
+ result: Tuple[str, Dict[str, Tuple[bool, bool]]] = run_progress_get_state(library)
70
+ python_exe, state_values = result
72
71
  state_values = dict(sorted(state_values.items()))
73
72
 
74
73
  console = Console()
@@ -76,7 +75,7 @@ def jobs_state(
76
75
  max_lib_length = max((len(lib) for lib in state_values.keys()), default=len(header_1))
77
76
  padding = max_lib_length + 9
78
77
 
79
- console.print(f"Executable: {sys.executable}")
78
+ console.print(f"Executable: {python_exe}")
80
79
  console.print(f"\n{header_1:<{padding}}{header_2}", style="bold")
81
80
 
82
81
  for lib, (installed, enabled) in state_values.items():
@@ -9,17 +9,10 @@ Module supporting 'qbraid jobs enable/disable braket' and commands.
9
9
  import logging
10
10
  import os
11
11
  import subprocess
12
- import sys
13
12
  from pathlib import Path
14
13
  from typing import Optional, Tuple
15
14
 
16
15
  import typer
17
- from qbraid_core.system import (
18
- QbraidSystemError,
19
- get_active_site_packages_path,
20
- get_latest_package_version,
21
- get_local_package_version,
22
- )
23
16
 
24
17
  from qbraid_cli.exceptions import QbraidException
25
18
  from qbraid_cli.handlers import handle_error, handle_filesystem_operation, run_progress_task
@@ -28,33 +21,38 @@ logging.basicConfig(level=logging.INFO)
28
21
  logger = logging.getLogger(__name__)
29
22
 
30
23
 
31
- def get_package_data(package: str) -> Tuple[str, str, str]:
24
+ def get_package_data(package: str) -> Tuple[str, str, str, str]:
32
25
  """Retrieve package version and location data.
33
26
 
34
27
  Args:
35
28
  package (str): The name of the package to retrieve data for.
36
29
 
37
30
  Returns:
38
- Tuple[str, str, str]: The installed and latest versions of the package, and the
39
- local site-packages path where it is / would be installed.
31
+ Tuple[str, str, str, str]: The installed and latest versions of the package, and the
32
+ local site-packages path where it is / would be installed.
40
33
 
41
34
  Raises:
42
35
  QbraidException: If package version or location data cannot be retrieved.
43
36
 
44
37
  """
38
+ # pylint: disable=import-outside-toplevel
39
+ from qbraid_core.system import (
40
+ QbraidSystemError,
41
+ get_active_python_path,
42
+ get_active_site_packages_path,
43
+ get_latest_package_version,
44
+ get_local_package_version,
45
+ )
45
46
 
46
47
  try:
47
- installed_version = get_local_package_version(package)
48
+ python_pathlib = get_active_python_path()
49
+ site_packages_path = get_active_site_packages_path(python_path=python_pathlib)
50
+ installed_version = get_local_package_version(package, python_path=python_pathlib)
48
51
  latest_version = get_latest_package_version(package)
49
52
  except QbraidSystemError as err:
50
- raise QbraidException("Failed to retrieve package version information") from err
51
-
52
- try:
53
- site_packages_path = get_active_site_packages_path()
54
- except QbraidSystemError as err:
55
- raise QbraidException("Failed to retrieve site-package location") from err
53
+ raise QbraidException("Failed to retrieve required system and/or package metadata") from err
56
54
 
57
- return installed_version, latest_version, site_packages_path
55
+ return installed_version, latest_version, str(site_packages_path), str(python_pathlib)
58
56
 
59
57
 
60
58
  def confirm_updates(
@@ -117,62 +115,39 @@ def confirm_updates(
117
115
  typer.echo("\nqBraidSystemExit: Exiting.")
118
116
  raise typer.Exit()
119
117
 
120
- typer.echo("")
121
-
122
118
 
123
119
  def aws_configure_dummy() -> None:
124
120
  """
125
121
  Initializes AWS configuration and credentials files with placeholder values.
126
122
 
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
123
  """
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)
124
+ from qbraid_core.services.quantum.proxy_braket import aws_configure
150
125
 
151
126
  try:
152
- handle_filesystem_operation(configure_aws, aws_dir)
127
+ handle_filesystem_operation(aws_configure, Path.home() / ".aws")
153
128
  except QbraidException:
154
129
  handle_error(message="Failed to configure qBraid quantum jobs.")
155
130
 
156
131
 
157
132
  def enable_braket(auto_confirm: bool = False):
158
133
  """Enable qBraid quantum jobs for Amazon Braket."""
159
- installed, latest, path = run_progress_task(
134
+ installed, latest, path, python_exe = run_progress_task(
160
135
  get_package_data, "boto3", description="Solving environment..."
161
136
  )
162
137
 
163
138
  if not auto_confirm:
164
139
  confirm_updates("enable", path, installed_version=installed, latest_version=latest)
140
+ typer.echo("")
165
141
 
166
142
  aws_configure_dummy() # TODO: possibly add another confirmation for writing aws config files
143
+
167
144
  try:
168
- subprocess.check_call([sys.executable, "-m", "pip", "install", "--upgrade", "boto3"])
145
+ subprocess.check_call([python_exe, "-m", "pip", "install", "--upgrade", "boto3"])
146
+ subprocess.check_call([python_exe, "-m", "pip", "uninstall", "botocore", "-y", "--quiet"])
169
147
  subprocess.check_call(
170
- [sys.executable, "-m", "pip", "uninstall", "botocore", "-y", "--quiet"]
148
+ [python_exe, "-m", "pip", "install", "git+https://github.com/qBraid/botocore.git"]
171
149
  )
172
- subprocess.check_call(
173
- [sys.executable, "-m", "pip", "install", "git+https://github.com/qBraid/botocore.git"]
174
- )
175
- except subprocess.CalledProcessError:
150
+ except (subprocess.CalledProcessError, FileNotFoundError):
176
151
  handle_error(message="Failed to enable qBraid quantum jobs.")
177
152
 
178
153
  typer.secho("\nSuccessfully enabled qBraid quantum jobs.", fg=typer.colors.GREEN, bold=True)
@@ -182,18 +157,19 @@ def enable_braket(auto_confirm: bool = False):
182
157
  def disable_braket(auto_confirm: bool = False):
183
158
  """Disable qBraid quantum jobs for Amazon Braket."""
184
159
  package = "botocore"
185
- installed, latest, path = run_progress_task(
160
+ installed, latest, path, python_exe = run_progress_task(
186
161
  get_package_data, package, description="Solving environment..."
187
162
  )
188
163
  package = f"{package}~={installed}" if installed < latest else package
189
164
 
190
165
  if not auto_confirm:
191
166
  confirm_updates("disable", path)
167
+ typer.echo("")
192
168
 
193
169
  try:
194
170
  subprocess.check_call(
195
171
  [
196
- sys.executable,
172
+ python_exe,
197
173
  "-m",
198
174
  "pip",
199
175
  "install",
@@ -202,7 +178,7 @@ def disable_braket(auto_confirm: bool = False):
202
178
  ],
203
179
  stderr=subprocess.DEVNULL,
204
180
  )
205
- except subprocess.CalledProcessError:
181
+ except (subprocess.CalledProcessError, FileNotFoundError):
206
182
  handle_error(message="Failed to disable qBraid quantum jobs.")
207
183
 
208
184
  typer.secho("\nSuccessfully disabled qBraid quantum jobs.", fg=typer.colors.GREEN, bold=True)
@@ -5,39 +5,59 @@
5
5
  Module for validating command arguments for qBraid Quantum Jobs.
6
6
 
7
7
  """
8
-
9
- from typing import Callable, Dict, Optional, Tuple
8
+ import sys
9
+ from typing import Any, Callable, Dict, Optional, Tuple
10
10
 
11
11
  import typer
12
- from qbraid_core.services.quantum.proxy import SUPPORTED_QJOB_LIBS, quantum_lib_proxy_state
13
12
  from rich.console import Console
14
13
 
15
14
  from qbraid_cli.handlers import handle_error, run_progress_task, validate_item
16
15
 
16
+ LEGACY_ARGS: Dict[str, str] = {
17
+ "amazon_braket": "braket",
18
+ "aws_braket": "braket",
19
+ }
20
+
17
21
 
18
22
  def validate_library(value: str) -> str:
19
23
  """Validate quantum jobs library."""
20
- return validate_item(value, SUPPORTED_QJOB_LIBS, "Library")
24
+ # pylint:disable-next=import-outside-toplevel
25
+ from qbraid_core.services.quantum.proxy import SUPPORTED_QJOB_LIBS
26
+
27
+ qjobs_libs = list(SUPPORTED_QJOB_LIBS.keys())
21
28
 
29
+ if value in LEGACY_ARGS:
30
+ old_value = value
31
+ value = LEGACY_ARGS[value]
22
32
 
23
- def get_state(library: Optional[str] = None) -> Dict[str, Tuple[bool, bool]]:
33
+ console = Console()
34
+ console.print(
35
+ f"[red]DeprecationWarning:[/red] Argument '{old_value}' "
36
+ f"is deprecated. Use '{value}' instead.\n"
37
+ )
38
+
39
+ return validate_item(value, qjobs_libs, "Library")
40
+
41
+
42
+ def get_state(library: Optional[str] = None) -> Tuple[str, Dict[str, Tuple[bool, bool]]]:
24
43
  """Get the state of qBraid Quantum Jobs for the specified library."""
44
+ from qbraid_core.services.quantum import QuantumClient
25
45
 
26
- state_values = {}
46
+ jobs_state = QuantumClient.qbraid_jobs_state(device_lib=library)
27
47
 
28
- if library:
29
- libraries_to_check = [library]
30
- else:
31
- libraries_to_check = SUPPORTED_QJOB_LIBS
48
+ python_exe: str = jobs_state.get("exe", sys.executable)
49
+ libs_state: Dict[str, Any] = jobs_state.get("libs", {})
32
50
 
33
- for lib in libraries_to_check:
34
- state = quantum_lib_proxy_state(lib)
35
- state_values[lib] = state["supported"], state["enabled"]
51
+ state_values = {
52
+ lib: (state["supported"], state["enabled"]) for lib, state in libs_state.items()
53
+ }
36
54
 
37
- return state_values
55
+ return python_exe, state_values
38
56
 
39
57
 
40
- def run_progress_get_state(library: Optional[str] = None) -> Dict[str, Tuple[bool, bool]]:
58
+ def run_progress_get_state(
59
+ library: Optional[str] = None,
60
+ ) -> Tuple[str, Dict[str, Tuple[bool, bool]]]:
41
61
  """Run get state function with rich progress UI."""
42
62
  return run_progress_task(
43
63
  get_state,
@@ -53,21 +73,20 @@ def handle_jobs_state(
53
73
  action_callback: Callable[[], None],
54
74
  ) -> None:
55
75
  """Handle the common logic for enabling or disabling qBraid Quantum Jobs."""
56
- state_values: Dict[str, Tuple[bool, bool]] = run_progress_get_state(library)
76
+ _, state_values = run_progress_get_state(library)
57
77
  installed, enabled = state_values[library]
58
78
 
59
79
  if not installed:
60
- handle_error(message=f"{library} not installed.")
80
+ handle_error(
81
+ message=f"{library} not installed."
82
+ ) # TODO: Provide command to install library?
61
83
  if (enabled and action == "enable") or (not enabled and action == "disable"):
62
84
  action_color = "green" if enabled else "red"
63
85
  console = Console()
64
86
  console.print(
65
87
  f"\nqBraid quantum jobs already [bold {action_color}]{action}d[/bold {action_color}] "
66
- f"for [magenta]{library}[/magenta]."
67
- )
68
- console.print(
69
- "To check the state of all quantum jobs libraries in this environment, "
70
- "use: \n\n\t$ qbraid jobs state\n"
88
+ f"for [magenta]{library}[/magenta].\n\nCheck the state of all quantum jobs "
89
+ "libraries in this environment with: \n\n\t$ qbraid jobs state\n"
71
90
  )
72
91
  raise typer.Exit()
73
92
 
qbraid_cli/main.py CHANGED
@@ -7,8 +7,8 @@ Entrypoint for the qBraid CLI.
7
7
  """
8
8
 
9
9
  import typer
10
- import urllib3
11
10
 
11
+ from qbraid_cli.admin.app import admin_app
12
12
  from qbraid_cli.configure.app import configure_app
13
13
  from qbraid_cli.credits.app import credits_app
14
14
  from qbraid_cli.devices.app import devices_app
@@ -17,14 +17,14 @@ from qbraid_cli.jobs.app import jobs_app
17
17
  from qbraid_cli.kernels.app import kernels_app
18
18
 
19
19
  app = typer.Typer(context_settings={"help_option_names": ["-h", "--help"]})
20
+
21
+ app.add_typer(admin_app, name="admin")
20
22
  app.add_typer(configure_app, name="configure")
23
+ app.add_typer(credits_app, name="credits")
24
+ app.add_typer(devices_app, name="devices")
21
25
  app.add_typer(envs_app, name="envs")
22
26
  app.add_typer(jobs_app, name="jobs")
23
- app.add_typer(devices_app, name="devices")
24
27
  app.add_typer(kernels_app, name="kernels")
25
- app.add_typer(credits_app, name="credits")
26
-
27
- urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
28
28
 
29
29
 
30
30
  def version_callback(value: bool):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: qbraid-cli
3
- Version: 0.8.0.dev3
3
+ Version: 0.8.0.dev5
4
4
  Summary: Command Line Interface for interacting with all parts of the qBraid platform.
5
5
  Author-email: qBraid Development Team <contact@qbraid.com>
6
6
  License: Proprietary
@@ -29,7 +29,8 @@ Description-Content-Type: text/markdown
29
29
  Requires-Dist: typer >=0.12.1
30
30
  Requires-Dist: rich >=10.11.0
31
31
  Requires-Dist: jupyter-client <9.0.0,>=7.0.0
32
- Requires-Dist: qbraid-core >=0.1.1
32
+ Requires-Dist: ipykernel
33
+ Requires-Dist: qbraid-core >=0.1.3
33
34
  Provides-Extra: dev
34
35
  Requires-Dist: black ; extra == 'dev'
35
36
  Requires-Dist: isort ; extra == 'dev'
@@ -38,9 +39,11 @@ Requires-Dist: pytest ; extra == 'dev'
38
39
  Provides-Extra: docs
39
40
  Requires-Dist: sphinx ~=7.2.6 ; extra == 'docs'
40
41
  Requires-Dist: sphinx-rtd-theme <2.1,>=1.3 ; extra == 'docs'
41
- Requires-Dist: docutils <0.21 ; extra == 'docs'
42
+ Requires-Dist: docutils <0.22 ; extra == 'docs'
42
43
  Requires-Dist: toml ; extra == 'docs'
43
44
  Requires-Dist: build ; extra == 'docs'
45
+ Requires-Dist: m2r ; extra == 'docs'
46
+ Requires-Dist: typer ; extra == 'docs'
44
47
  Provides-Extra: jobs
45
48
  Requires-Dist: amazon-braket-sdk >=1.48.1 ; extra == 'jobs'
46
49
 
@@ -1,8 +1,12 @@
1
1
  qbraid_cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- qbraid_cli/_version.py,sha256=gmvID9vFrR93SKxjTAMGcHF8k0zAbpA7V0aBbjfr5jw,424
2
+ qbraid_cli/_version.py,sha256=rUwu2eja7AS4Qp4mUrT-oC2PaWQWiRi_YNlcgdK7tAE,424
3
3
  qbraid_cli/exceptions.py,sha256=KjlhYJhSHMVazaNiBjD_Ur06w4sekP8zRsFzBdyIpno,672
4
- qbraid_cli/handlers.py,sha256=rGxHrwrPHvwP3CKVlJSCZ_KkgGvFlLXd3SsxcC4LqS0,6306
5
- qbraid_cli/main.py,sha256=ko3c8fkzwcNlNb0AFLFgwlSoOOC4DJgeHlRuHbz-dyw,2504
4
+ qbraid_cli/handlers.py,sha256=i3vdRtdy4bZKg3j6fwfVMz1ddhMgzlc2hhmj-vewxpI,6542
5
+ qbraid_cli/main.py,sha256=IRKazFqtFpoiq_xOtqb-IXDKAVs4lacFIRCQCoiGNF4,2503
6
+ qbraid_cli/admin/__init__.py,sha256=Suo_L1_yBodCvLM_fpw8gRIhD4mVVOXKObtxeoMaBVo,150
7
+ qbraid_cli/admin/app.py,sha256=__6lo-iFsbfz-ayD1-AS8X1z_gYhCad1NK17hnrL7HY,1451
8
+ qbraid_cli/admin/headers.py,sha256=oE2Ry9221ZV4tgYqFJNHAPilDw72xR3LqG_gBw7BFxM,6667
9
+ qbraid_cli/admin/validation.py,sha256=LkAVXlHtM0MhCa34MIWrfX59wGXMVlZmdVB4-AQ8fBk,1003
6
10
  qbraid_cli/configure/__init__.py,sha256=6GU7vR6JYRGcMsmdrpFbwLO5VSUmnLgwSbtmGWMQND4,158
7
11
  qbraid_cli/configure/actions.py,sha256=3rrWHaCAsogyx0Ll-lcjbSzldD4kPuz1z6VQiWebSWw,3203
8
12
  qbraid_cli/configure/app.py,sha256=vcPu1Npf8sfGtWGQrjDJQG5vCdeUa3nlpEnZMlVLlWM,1615
@@ -10,20 +14,20 @@ qbraid_cli/credits/__init__.py,sha256=t-3XAJFAXiu_jI4sgjaIOuNne_AoSYaSEsi-SSRkvP
10
14
  qbraid_cli/credits/app.py,sha256=iHikmjx8pylMFNzHckuauOg-Nb9pS7xQq_H75ibVJig,774
11
15
  qbraid_cli/devices/__init__.py,sha256=_PU3eMQRV4DkPw-oCmfCPh8EbVmgG76ieEKuNsY9Xqc,154
12
16
  qbraid_cli/devices/app.py,sha256=zxSxrEQn7irkJoME4S_CBnRqWeB8cqPaBsIMfpdYFk0,2530
13
- qbraid_cli/devices/validation.py,sha256=Zt0mdg4nXHz-7yGP3qH6UwVoF18yrqW_4jdS4kiFKsQ,810
17
+ qbraid_cli/devices/validation.py,sha256=YhShyUufgrKnx2XjXOXF-PqFJYklJT9CgeqIwKcNam4,809
14
18
  qbraid_cli/envs/__init__.py,sha256=YgIoMWxfGqzmwfypO5JHYuCOu6BfFwb9NHgQel1IJM8,148
15
19
  qbraid_cli/envs/activate.py,sha256=VpvVYSfQDlcmlNWJOgkLIQ2p8YXPPLG8Jbl5t8GHUDw,2140
16
20
  qbraid_cli/envs/app.py,sha256=t6bRwJGy-M3PAu870ZsttsM8tpSB0OFasgCJiV9nTSA,8620
17
21
  qbraid_cli/envs/create.py,sha256=uCRex_TcFYw26jUOU06Ta5I8Mq5pRqLVaOE6MxrrExs,4337
18
22
  qbraid_cli/envs/data_handling.py,sha256=mTVzsj6KleeeYDKGhgD-IesF9KQQMSszKFSEo8Wrv9w,4001
19
23
  qbraid_cli/jobs/__init__.py,sha256=bj9XmZ4JL8OtMMZbHIu-DPhpOMXGLSB-W1b0wO7wKro,148
20
- qbraid_cli/jobs/app.py,sha256=LsyYFh2949-6eCVfdzcY-Nvt4rSN5lNBDZ57j0OBzWE,4870
21
- qbraid_cli/jobs/toggle_braket.py,sha256=2vCkKcDsQmVYpElHwOI-fQCVbIH-0HBnnDZSfp_bSlk,7553
22
- qbraid_cli/jobs/validation.py,sha256=6QKkFINk8Jqw1wuwPivbD5HuFTzT1cUT_G2WVqaKcnc,2405
24
+ qbraid_cli/jobs/app.py,sha256=kmg9mYla3Nd7EdjQlFu7IOvm7sejLNfPPA6Qeet-IfE,4898
25
+ qbraid_cli/jobs/toggle_braket.py,sha256=d5C_Di80jWMFlh-77eH8YY9pjMKWXK5abenUDtPlE_I,6662
26
+ qbraid_cli/jobs/validation.py,sha256=xNbjUggMhUs4wzkuRm4PuFPi_wrElYicUgYXLznHz3U,2983
23
27
  qbraid_cli/kernels/__init__.py,sha256=VhpBota_v7OoiGxrPCqJU4XBVcolf81mbCYGSxXzVhc,154
24
28
  qbraid_cli/kernels/app.py,sha256=ZJWVdKzCDfzGnA1pqp01vDbE7fh8p84jC-y6DDgWlxc,3373
25
- qbraid_cli-0.8.0.dev3.dist-info/METADATA,sha256=Ud547dThxdfsRnAXTcTy_J2s3xQcLVglP9houT2FNSw,5818
26
- qbraid_cli-0.8.0.dev3.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
27
- qbraid_cli-0.8.0.dev3.dist-info/entry_points.txt,sha256=c5ZJ7NjbxhDqMpou9q5F03_b_KG34HzFDijIDmEIwgQ,47
28
- qbraid_cli-0.8.0.dev3.dist-info/top_level.txt,sha256=LTYJgeYSCHo9Il8vZu0yIPuGdGyNaIw6iRy6BeoZo8o,11
29
- qbraid_cli-0.8.0.dev3.dist-info/RECORD,,
29
+ qbraid_cli-0.8.0.dev5.dist-info/METADATA,sha256=emAQ5AjqtbZ9_l0lSBUtU4Jizzrru3GPPsxnUfriZds,5919
30
+ qbraid_cli-0.8.0.dev5.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
31
+ qbraid_cli-0.8.0.dev5.dist-info/entry_points.txt,sha256=c5ZJ7NjbxhDqMpou9q5F03_b_KG34HzFDijIDmEIwgQ,47
32
+ qbraid_cli-0.8.0.dev5.dist-info/top_level.txt,sha256=LTYJgeYSCHo9Il8vZu0yIPuGdGyNaIw6iRy6BeoZo8o,11
33
+ qbraid_cli-0.8.0.dev5.dist-info/RECORD,,