qbraid-cli 0.9.0a0__tar.gz → 0.9.2__tar.gz

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 (110) hide show
  1. qbraid_cli-0.9.2/.github/workflows/docs-pr.yml +128 -0
  2. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/.readthedocs.yml +1 -1
  3. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/CONTRIBUTING.md +6 -0
  4. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/PKG-INFO +3 -2
  5. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/docs/index.rst +2 -1
  6. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/pyproject.toml +3 -2
  7. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/qbraid_cli/_version.py +2 -2
  8. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/qbraid_cli/account/app.py +2 -2
  9. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/qbraid_cli/admin/app.py +3 -1
  10. qbraid_cli-0.9.2/qbraid_cli/chat/__init__.py +11 -0
  11. qbraid_cli-0.9.2/qbraid_cli/chat/app.py +76 -0
  12. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/qbraid_cli/devices/app.py +2 -2
  13. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/qbraid_cli/envs/app.py +4 -4
  14. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/qbraid_cli/handlers.py +19 -5
  15. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/qbraid_cli/jobs/app.py +2 -2
  16. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/qbraid_cli/jobs/toggle_braket.py +1 -1
  17. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/qbraid_cli/kernels/app.py +1 -1
  18. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/qbraid_cli/main.py +41 -9
  19. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/qbraid_cli/pip/app.py +1 -2
  20. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/qbraid_cli.egg-info/PKG-INFO +3 -2
  21. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/qbraid_cli.egg-info/SOURCES.txt +4 -0
  22. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/qbraid_cli.egg-info/requires.txt +2 -1
  23. qbraid_cli-0.9.2/tests/conftest.py +35 -0
  24. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/tests/devices/test_devices_list.py +4 -16
  25. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/tests/jobs/test_jobs_list.py +3 -13
  26. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/.env.example +0 -0
  27. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  28. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  29. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  30. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/.github/workflows/bump-version.yml +0 -0
  31. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/.github/workflows/docs.yml +0 -0
  32. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/.github/workflows/format.yml +0 -0
  33. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/.github/workflows/main.yml +0 -0
  34. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/.github/workflows/pre-release.yml +0 -0
  35. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/.github/workflows/publish.yml +0 -0
  36. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/.github/workflows/tag-on-merge.yml +0 -0
  37. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/.gitignore +0 -0
  38. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/LICENSE +0 -0
  39. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/MANIFEST.IN +0 -0
  40. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/Makefile +0 -0
  41. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/README.md +0 -0
  42. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/docs/Makefile +0 -0
  43. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/docs/_static/favicon.ico +0 -0
  44. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/docs/_static/logo.png +0 -0
  45. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/docs/_static/style/custom.css +0 -0
  46. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/docs/_static/style/s4defs-roles.css +0 -0
  47. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/docs/conf.py +0 -0
  48. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/docs/make.bat +0 -0
  49. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/docs/requirements.txt +0 -0
  50. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/qbraid_cli/__init__.py +0 -0
  51. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/qbraid_cli/account/__init__.py +0 -0
  52. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/qbraid_cli/admin/__init__.py +0 -0
  53. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/qbraid_cli/admin/headers.py +0 -0
  54. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/qbraid_cli/admin/validation.py +0 -0
  55. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/qbraid_cli/configure/__init__.py +0 -0
  56. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/qbraid_cli/configure/actions.py +0 -0
  57. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/qbraid_cli/configure/app.py +0 -0
  58. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/qbraid_cli/devices/__init__.py +0 -0
  59. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/qbraid_cli/devices/validation.py +0 -0
  60. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/qbraid_cli/envs/__init__.py +0 -0
  61. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/qbraid_cli/envs/activate.py +0 -0
  62. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/qbraid_cli/envs/create.py +0 -0
  63. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/qbraid_cli/envs/data_handling.py +0 -0
  64. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/qbraid_cli/exceptions.py +0 -0
  65. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/qbraid_cli/jobs/__init__.py +0 -0
  66. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/qbraid_cli/jobs/validation.py +0 -0
  67. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/qbraid_cli/kernels/__init__.py +0 -0
  68. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/qbraid_cli/pip/__init__.py +0 -0
  69. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/qbraid_cli/pip/hooks.py +0 -0
  70. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/qbraid_cli/py.typed +0 -0
  71. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/qbraid_cli.egg-info/dependency_links.txt +0 -0
  72. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/qbraid_cli.egg-info/entry_points.txt +0 -0
  73. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/qbraid_cli.egg-info/top_level.txt +0 -0
  74. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/setup.cfg +0 -0
  75. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/tests/__init__.py +0 -0
  76. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/tests/account/__init__.py +0 -0
  77. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/tests/account/test_account_credits.py +0 -0
  78. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/tests/admin/test_headers.py +0 -0
  79. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/tests/configure/__init__.py +0 -0
  80. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/tests/configure/test_configure_prompt_for_config.py +0 -0
  81. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/tests/configure/test_configure_set.py +0 -0
  82. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/tests/configure/test_configure_validate_input.py +0 -0
  83. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/tests/devices/__init__.py +0 -0
  84. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/tests/devices/test_devices_validations.py +0 -0
  85. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/tests/envs/__init__.py +0 -0
  86. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/tests/envs/test_envs_activate.py +0 -0
  87. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/tests/envs/test_envs_activate_find_shell_rc.py +0 -0
  88. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/tests/envs/test_envs_activate_print_command.py +0 -0
  89. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/tests/envs/test_envs_activate_pyenv.py +0 -0
  90. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/tests/envs/test_envs_list.py +0 -0
  91. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/tests/envs/test_envs_remove.py +0 -0
  92. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/tests/jobs/__init__.py +0 -0
  93. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/tests/jobs/test_jobs_disable.py +0 -0
  94. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/tests/jobs/test_jobs_enable.py +0 -0
  95. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/tests/jobs/test_jobs_state.py +0 -0
  96. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/tests/jobs/test_jobs_toggle_braket_confirm.py +0 -0
  97. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/tests/jobs/test_jobs_toggle_braket_disable.py +0 -0
  98. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/tests/jobs/test_jobs_toggle_braket_enable.py +0 -0
  99. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/tests/jobs/test_jobs_toggle_braket_get_data.py +0 -0
  100. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/tests/jobs/test_jobs_validate_get_state.py +0 -0
  101. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/tests/jobs/test_jobs_validate_handle_state.py +0 -0
  102. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/tests/jobs/test_jobs_validate_library.py +0 -0
  103. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/tests/kernels/__init__.py +0 -0
  104. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/tests/kernels/test_kernels_list.py +0 -0
  105. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/tools/bump_version.py +0 -0
  106. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/tools/create_dev_build.sh +0 -0
  107. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/tools/install_wheel_extras.sh +0 -0
  108. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/tools/split_md.py +0 -0
  109. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/tools/split_rst.py +0 -0
  110. {qbraid_cli-0.9.0a0 → qbraid_cli-0.9.2}/tools/stamp_pre_release.py +0 -0
@@ -0,0 +1,128 @@
1
+ name: Open Docs PR
2
+
3
+ on:
4
+ pull_request:
5
+ types: [closed]
6
+
7
+ jobs:
8
+ generate-docs-assets:
9
+ if: github.event.pull_request.merged == true && github.event.pull_request.user.login == 'github-actions[bot]' && startsWith(github.event.pull_request.title, 'Bump project version to ')
10
+ runs-on: ubuntu-latest
11
+ outputs:
12
+ cli_version: ${{ steps.get_version.outputs.version }}
13
+ steps:
14
+ - name: Checkout code
15
+ uses: actions/checkout@v4
16
+ with:
17
+ ref: main
18
+
19
+ - name: Install dependencies
20
+ run: |
21
+ python -m pip install --upgrade pip setuptools build
22
+ python -m pip install -r docs/requirements.txt
23
+
24
+ - name: Build & install package
25
+ run: |
26
+ make build
27
+ tools/install_wheel_extras.sh dist --extra envs
28
+
29
+ - name: Get qbraid-cli version
30
+ id: get_version
31
+ run: |
32
+ VERSION=$(qbraid --version | grep -o '[0-9]*\.[0-9]*\.[0-9]*')
33
+ echo "version=$VERSION" >> $GITHUB_OUTPUT
34
+
35
+ - name: Generate docs assets
36
+ run: |
37
+ make docs-mdx
38
+
39
+ - name: Upload docs assets
40
+ uses: actions/upload-artifact@v4
41
+ with:
42
+ name: api-reference
43
+ path: docs/tree/qbraid*.mdx
44
+
45
+ commit-and-pr:
46
+ if: github.event.pull_request.merged == true && github.event.pull_request.user.login == 'github-actions[bot]' && startsWith(github.event.pull_request.title, 'Bump project version to ')
47
+ runs-on: ubuntu-latest
48
+ needs: generate-docs-assets
49
+ permissions:
50
+ contents: write
51
+ pull-requests: write
52
+
53
+ steps:
54
+ - name: Download docs assets
55
+ uses: actions/download-artifact@v4
56
+ with:
57
+ name: api-reference
58
+ path: ./api-reference
59
+
60
+ - name: Checkout qBraid/docs repo
61
+ uses: actions/checkout@v4
62
+ with:
63
+ repository: qBraid/docs
64
+ token: ${{ secrets.BOT_TOKEN }}
65
+ path: ./qbraid_docs
66
+ ref: main
67
+
68
+ - name: Create feature branch
69
+ run: |
70
+ cd qbraid_docs
71
+ git checkout -b qbraid-cli-bot/${{ github.run_id }}
72
+
73
+ - name: Update docs in qBraid/docs
74
+ run: |
75
+ rm -f qbraid_docs/cli/api-reference/*
76
+ cp api-reference/qbraid*.mdx qbraid_docs/cli/api-reference/
77
+
78
+ - name: Inject version
79
+ run: |
80
+ VERSION=${{ needs.generate-docs-assets.outputs.cli_version }}
81
+ sed -i "6iVersion: [$VERSION](https://pypi.org/project/qbraid-cli/$VERSION)\n" qbraid_docs/cli/api-reference/qbraid.mdx
82
+
83
+ - name: Set up Node.js
84
+ uses: actions/setup-node@v4
85
+ with:
86
+ node-version: '22'
87
+
88
+ - name: Install dependencies
89
+ run: |
90
+ cd qbraid_docs
91
+ npm install
92
+
93
+ - name: Run prettier fixes
94
+ run: |
95
+ cd qbraid_docs
96
+ npx prettier --write cli/api-reference/qbraid*.mdx
97
+
98
+ - name: Setup Git config
99
+ run: |
100
+ git config --global user.name 'qbraidTeam'
101
+ git config --global user.email 'qbraid.team@qbraid.com'
102
+
103
+ - name: Commit and push changes
104
+ id: commit_and_push
105
+ run: |
106
+ cd qbraid_docs
107
+ git add cli/api-reference/
108
+ git commit -m "qBraid-CLI API reference docs update for version $VERSION"
109
+ git push origin qbraid-cli-bot/${{ github.run_id }}
110
+
111
+ - name: Create Pull Request
112
+ id: create_pr
113
+ run: |
114
+ cd qbraid_docs
115
+ VERSION=${{ needs.generate-docs-assets.outputs.cli_version }}
116
+ PR_URL=$(gh pr create -B main -H qbraid-cli-bot/${{ github.run_id }} --title "Update qBraid-CLI version $VERSION" --body "This PR updates the qBraid-CLI API reference docs for the latest release version $VERSION")
117
+ PR_NUMBER=$(echo "$PR_URL" | grep -o '[0-9]*$')
118
+ echo "url=$PR_URL" >> $GITHUB_OUTPUT
119
+ echo "number=$PR_NUMBER" >> $GITHUB_OUTPUT
120
+ env:
121
+ GH_TOKEN: ${{ secrets.BOT_TOKEN }}
122
+
123
+ - name: Summary
124
+ run: |
125
+ VERSION=${{ needs.generate-docs-assets.outputs.cli_version }}
126
+ PR_URL=${{ steps.create_pr.outputs.url }}
127
+ PR_NUMBER=${{ steps.create_pr.outputs.number }}
128
+ echo "Opened PR [#$PR_NUMBER]($PR_URL) to update CLI docs for version **$VERSION**." >> $GITHUB_STEP_SUMMARY
@@ -13,7 +13,7 @@ build:
13
13
  - python -m pip install -r docs/requirements.txt
14
14
  - python -m pip install build
15
15
  - python -m build .
16
- - python -m pip install dist/*.whl
16
+ - tools/install_wheel_extras.sh dist --extra envs
17
17
  - mkdir -p docs/tree
18
18
  - rm -f docs/tree/*.rst
19
19
  - typer qbraid_cli.main utils docs --name=qbraid --output=docs/tree/qbraid.md
@@ -39,6 +39,12 @@ To view available `make` commands, run:
39
39
  make help
40
40
  ```
41
41
 
42
+ To test out changes on the command line with re-installing each time:
43
+
44
+ ```bash
45
+ python3 qbraid_cli/main.py [OPTIONS] COMMAND [ARGS]...
46
+ ```
47
+
42
48
  ## Testing
43
49
 
44
50
  Install test dependencies:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: qbraid-cli
3
- Version: 0.9.0a0
3
+ Version: 0.9.2
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
  License-File: LICENSE
30
30
  Requires-Dist: typer>=0.12.1
31
31
  Requires-Dist: rich>=10.11.0
32
- Requires-Dist: qbraid-core>=0.1.28
32
+ Requires-Dist: click
33
+ Requires-Dist: qbraid-core>=0.1.31
33
34
  Provides-Extra: jobs
34
35
  Requires-Dist: amazon-braket-sdk>=1.48.1; extra == "jobs"
35
36
  Provides-Extra: envs
@@ -120,4 +120,5 @@ by disabling quantum jobs:
120
120
  tree/qbraid_envs
121
121
  tree/qbraid_jobs
122
122
  tree/qbraid_kernels
123
- tree/qbraid_pip
123
+ tree/qbraid_pip
124
+ tree/qbraid_chat
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "qbraid-cli"
7
- version = "0.9.0a0"
7
+ version = "0.9.2"
8
8
  description = "Command Line Interface for interacting with all parts of the qBraid platform."
9
9
  readme = "README.md"
10
10
  authors = [{ name = "qBraid Development Team", email = "contact@qbraid.com" }]
@@ -30,7 +30,8 @@ classifiers = [
30
30
  dependencies = [
31
31
  "typer>=0.12.1",
32
32
  "rich>=10.11.0",
33
- "qbraid-core>=0.1.28",
33
+ "click",
34
+ "qbraid-core>=0.1.31",
34
35
  ]
35
36
  requires-python = ">= 3.9"
36
37
 
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '0.1.dev1+ge41229b.d20241106'
16
- __version_tuple__ = version_tuple = (0, 1, 'dev1', 'ge41229b.d20241106')
15
+ __version__ = version = '0.1.dev1+gd39b277'
16
+ __version_tuple__ = version_tuple = (0, 1, 'dev1', 'gd39b277')
@@ -13,7 +13,7 @@ import typer
13
13
 
14
14
  from qbraid_cli.handlers import run_progress_task
15
15
 
16
- account_app = typer.Typer(help="Manage qBraid account.")
16
+ account_app = typer.Typer(help="Manage qBraid account.", no_args_is_help=True)
17
17
 
18
18
 
19
19
  @account_app.command(name="credits")
@@ -28,7 +28,7 @@ def account_credits():
28
28
 
29
29
  qbraid_credits: float = run_progress_task(get_credits)
30
30
  typer.secho(
31
- f"\n{typer.style('qBraid credits remaining:')} "
31
+ f"{typer.style('qBraid credits remaining:')} "
32
32
  f"{typer.style(f'{qbraid_credits:.4f}', fg=typer.colors.MAGENTA, bold=True)}",
33
33
  nl=True, # Ensure a newline after output (default is True)
34
34
  )
@@ -14,7 +14,9 @@ from qbraid_cli.admin.headers import check_and_fix_headers
14
14
  from qbraid_cli.admin.validation import validate_header_type, validate_paths_exist
15
15
 
16
16
  admin_app = typer.Typer(
17
- help="CI/CD commands for qBraid maintainers.", pretty_exceptions_show_locals=False
17
+ help="CI/CD commands for qBraid maintainers.",
18
+ pretty_exceptions_show_locals=False,
19
+ no_args_is_help=True,
18
20
  )
19
21
 
20
22
 
@@ -0,0 +1,11 @@
1
+ # Copyright (c) 2024, qBraid Development Team
2
+ # All rights reserved.
3
+
4
+ """
5
+ Module defining the qbraid chat namespace
6
+
7
+ """
8
+
9
+ from .app import ChatFormat, list_models_callback, prompt_callback
10
+
11
+ __all__ = ["list_models_callback", "prompt_callback", "ChatFormat"]
@@ -0,0 +1,76 @@
1
+ # Copyright (c) 2024, qBraid Development Team
2
+ # All rights reserved.
3
+
4
+ """
5
+ Module defining commands in the 'qbraid chat' namespace.
6
+
7
+ """
8
+ from enum import Enum
9
+
10
+ from rich.console import Console
11
+ from rich.table import Table
12
+
13
+ from qbraid_cli.handlers import handle_error, run_progress_task
14
+
15
+
16
+ class ChatFormat(str, Enum):
17
+ """Format of the response from the chat service."""
18
+
19
+ text = "text" # pylint: disable=invalid-name
20
+ code = "code" # pylint: disable=invalid-name
21
+
22
+
23
+ def list_models_callback():
24
+ """List available chat models."""
25
+ # pylint: disable-next=import-outside-toplevel
26
+ from qbraid_core.services.chat import ChatClient
27
+
28
+ client = ChatClient()
29
+
30
+ models = run_progress_task(
31
+ client.get_models,
32
+ description="Connecting to chat service...",
33
+ include_error_traceback=False,
34
+ )
35
+
36
+ console = Console()
37
+ table = Table(title="Available Chat Models\n", show_lines=True, title_justify="left")
38
+
39
+ table.add_column("Model", style="cyan", no_wrap=True)
40
+ table.add_column("Pricing [not bold](1k tokens ~750 words)", style="magenta")
41
+ table.add_column("Description", style="green")
42
+
43
+ for model in models:
44
+ table.add_row(
45
+ model["model"],
46
+ f"{model['pricing']['input']} credits / 1M input tokens\n"
47
+ f"{model['pricing']['output']} credits / 1M output tokens",
48
+ model["description"],
49
+ )
50
+
51
+ console.print(table)
52
+
53
+
54
+ def prompt_callback(prompt: str, model: str, response_format: ChatFormat, stream: bool):
55
+ """Send a chat prompt to the chat service."""
56
+ # pylint: disable-next=import-outside-toplevel
57
+ from qbraid_core.services.chat import ChatClient, ChatServiceRequestError
58
+
59
+ client = ChatClient()
60
+
61
+ if stream:
62
+ try:
63
+ for chunk in client.chat_stream(prompt, model, response_format):
64
+ print(chunk, end="")
65
+ except ChatServiceRequestError as err:
66
+ handle_error(message=str(err), include_traceback=False)
67
+ else:
68
+ content = run_progress_task(
69
+ client.chat,
70
+ prompt,
71
+ model,
72
+ response_format,
73
+ description="Connecting to chat service...",
74
+ include_error_traceback=False,
75
+ )
76
+ print(content)
@@ -14,7 +14,7 @@ from rich.console import Console
14
14
  from qbraid_cli.devices.validation import validate_provider, validate_status, validate_type
15
15
  from qbraid_cli.handlers import run_progress_task
16
16
 
17
- devices_app = typer.Typer(help="Manage qBraid quantum devices.")
17
+ devices_app = typer.Typer(help="Manage qBraid quantum devices.", no_args_is_help=True)
18
18
 
19
19
 
20
20
  @devices_app.command(name="list")
@@ -60,7 +60,7 @@ def devices_list( # pylint: disable=too-many-branches
60
60
  header_3 = "ID"
61
61
  header_4 = "Status"
62
62
  console.print(
63
- f"\n[bold]{header_1.ljust(12)}{header_2.ljust(35)}{header_3.ljust(41)}{header_4}[/bold]"
63
+ f"[bold]{header_1.ljust(12)}{header_2.ljust(35)}{header_3.ljust(41)}{header_4}[/bold]"
64
64
  )
65
65
  for device_provider, device_name, device_id, device_status in device_data:
66
66
  if device_status == "ONLINE":
@@ -23,7 +23,7 @@ from qbraid_cli.handlers import QbraidException, run_progress_task
23
23
  if TYPE_CHECKING:
24
24
  from qbraid_core.services.environments.client import EnvironmentManagerClient as EMC
25
25
 
26
- envs_app = typer.Typer(help="Manage qBraid environments.")
26
+ envs_app = typer.Typer(help="Manage qBraid environments.", no_args_is_help=True)
27
27
 
28
28
 
29
29
  @envs_app.command(name="create")
@@ -88,7 +88,7 @@ def envs_create( # pylint: disable=too-many-statements
88
88
  slug_path = env_path / slug
89
89
  description = "None" if description == "" else description
90
90
 
91
- typer.echo("\n\n## qBraid Metadata ##\n")
91
+ typer.echo("## qBraid Metadata ##\n")
92
92
  typer.echo(f" name: {display_name}")
93
93
  typer.echo(f" description: {description}")
94
94
  typer.echo(f" tags: {tags}")
@@ -127,7 +127,7 @@ def envs_create( # pylint: disable=too-many-statements
127
127
 
128
128
  console = Console()
129
129
  console.print(
130
- f"\n[bold green]Successfully created qBraid environment: "
130
+ f"[bold green]Successfully created qBraid environment: "
131
131
  f"[/bold green][bold magenta]{name}[/bold magenta]\n"
132
132
  )
133
133
  typer.echo("# To activate this environment, use")
@@ -192,7 +192,7 @@ def envs_remove(
192
192
  description="Deleting local environment...",
193
193
  error_message="Failed to delete qBraid environment",
194
194
  )
195
- typer.echo(f"\nEnvironment '{name}' successfully removed.")
195
+ typer.echo(f"Environment '{name}' successfully removed.")
196
196
 
197
197
 
198
198
  @envs_app.command(name="list")
@@ -10,11 +10,12 @@ and executing operations with progress tracking within the qBraid CLI.
10
10
  import os
11
11
  import traceback
12
12
  from pathlib import Path
13
+ from time import sleep
13
14
  from typing import Any, Callable, Optional, Union
14
15
 
15
16
  import typer
16
17
  from rich.console import Console
17
- from rich.progress import Progress, SpinnerColumn, TextColumn
18
+ from rich.progress import Progress, SpinnerColumn, TaskID, TextColumn
18
19
 
19
20
  from .exceptions import DEFAULT_ERROR_MESSAGE, QbraidException
20
21
 
@@ -24,6 +25,14 @@ def _should_display_progress():
24
25
  return os.getenv("QBRAID_CLI_SHOW_PROGRESS", "true").lower() in ["true", "1", "t", "y", "yes"]
25
26
 
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
+
27
36
  def handle_error(
28
37
  error_type: Optional[str] = None, message: Optional[str] = None, include_traceback: bool = True
29
38
  ) -> None:
@@ -85,6 +94,7 @@ def run_progress_task(
85
94
  *args,
86
95
  description: Optional[str] = None,
87
96
  error_message: Optional[str] = None,
97
+ include_error_traceback: bool = True,
88
98
  **kwargs,
89
99
  ) -> Any:
90
100
  """
@@ -102,6 +112,8 @@ def run_progress_task(
102
112
  error_message (optional, str): Custom error message to display if the operation.
103
113
  fails. Defaults to None, in which case the
104
114
  exception's message is used.
115
+ include_error_traceback (bool): Whether to include the traceback in the error message.
116
+ Defaults to True.
105
117
  **kwargs: Arbitrary keyword arguments for the operation.
106
118
 
107
119
  Returns:
@@ -115,7 +127,7 @@ def run_progress_task(
115
127
  return operation(*args, **kwargs)
116
128
  except Exception as err: # pylint: disable=broad-exception-caught
117
129
  custom_message = error_message if error_message else str(err)
118
- return handle_error(message=custom_message)
130
+ return handle_error(message=custom_message, include_traceback=include_error_traceback)
119
131
 
120
132
  console = Console()
121
133
  with Progress(
@@ -128,12 +140,14 @@ def run_progress_task(
128
140
  task = progress.add_task(description, status="In Progress", total=None)
129
141
  try:
130
142
  result = operation(*args, **kwargs)
131
- progress.update(task, completed=100, status="Done")
143
+ _update_completed_task(progress, task, success=True)
132
144
  return result
133
145
  except Exception as err: # pylint: disable=broad-exception-caught
134
- progress.update(task, completed=100, status="Failed")
146
+ _update_completed_task(progress, task, success=False)
135
147
  custom_message = error_message if error_message else str(err)
136
- return handle_error(message=custom_message)
148
+ return handle_error(message=custom_message, include_traceback=include_error_traceback)
149
+ finally:
150
+ progress.remove_task(task)
137
151
 
138
152
 
139
153
  def _format_list_items(items: list[str]) -> str:
@@ -15,7 +15,7 @@ from qbraid_cli.handlers import handle_error, run_progress_task
15
15
  from qbraid_cli.jobs.toggle_braket import disable_braket, enable_braket
16
16
  from qbraid_cli.jobs.validation import handle_jobs_state, run_progress_get_state, validate_library
17
17
 
18
- jobs_app = typer.Typer(help="Manage qBraid quantum jobs.")
18
+ jobs_app = typer.Typer(help="Manage qBraid quantum jobs.", no_args_is_help=True)
19
19
 
20
20
 
21
21
  @jobs_app.command(name="enable")
@@ -120,7 +120,7 @@ def jobs_list(
120
120
  header_1 = "Job ID"
121
121
  header_2 = "Submitted"
122
122
  header_3 = "Status"
123
- console.print(f"\n[bold]{header_1.ljust(spacing)}{header_2.ljust(36)}{header_3}[/bold]")
123
+ console.print(f"[bold]{header_1.ljust(spacing)}{header_2.ljust(36)}{header_3}[/bold]")
124
124
  for job_id, submitted, status in job_data:
125
125
  if status == "COMPLETED":
126
126
  status_color = "green"
@@ -103,7 +103,7 @@ def confirm_updates(
103
103
  else:
104
104
  raise ValueError(f"Invalid mode: {mode}. Expected 'enable' or 'disable'.")
105
105
 
106
- typer.echo(f"\n==> WARNING: {provider}/{core_package} package required <==")
106
+ typer.echo(f"==> WARNING: {provider}/{core_package} package required <==")
107
107
  if (
108
108
  installed_version is not None
109
109
  and target_version is not None
@@ -11,7 +11,7 @@ from rich.console import Console
11
11
 
12
12
  from qbraid_cli.handlers import handle_error
13
13
 
14
- kernels_app = typer.Typer(help="Manage qBraid kernels.")
14
+ kernels_app = typer.Typer(help="Manage qBraid kernels.", no_args_is_help=True)
15
15
 
16
16
 
17
17
  @kernels_app.command(name="list")
@@ -6,18 +6,21 @@ Entrypoint for the qBraid CLI.
6
6
 
7
7
  """
8
8
 
9
+ import click
10
+ import rich
9
11
  import typer
10
12
 
11
- from qbraid_cli.account.app import account_app
12
- from qbraid_cli.admin.app import admin_app
13
- from qbraid_cli.configure.app import configure_app
14
- from qbraid_cli.devices.app import devices_app
15
- from qbraid_cli.jobs.app import jobs_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.jobs import jobs_app
16
19
 
17
20
  try:
18
- from qbraid_cli.envs.app import envs_app
19
- from qbraid_cli.kernels.app import kernels_app
20
- from qbraid_cli.pip.app import pip_app
21
+ from qbraid_cli.envs import envs_app
22
+ from qbraid_cli.kernels import kernels_app
23
+ from qbraid_cli.pip import pip_app
21
24
 
22
25
  ENVS_COMMANDS = True
23
26
  except ImportError:
@@ -67,7 +70,7 @@ def show_banner():
67
70
  typer.echo("")
68
71
  typer.echo("- Use 'qbraid --version' to see the current version.")
69
72
  typer.echo("")
70
- typer.echo("Reference Docs: https://docs.qbraid.com/cli/api-reference/qbraid")
73
+ rich.print("Reference Docs: https://docs.qbraid.com/cli/api-reference/qbraid")
71
74
 
72
75
 
73
76
  @app.callback(invoke_without_command=True)
@@ -87,5 +90,34 @@ def main(
87
90
  show_banner()
88
91
 
89
92
 
93
+ @app.command(help="Interact with qBraid AI chat service.", no_args_is_help=True)
94
+ def chat(
95
+ prompt: str = typer.Option(
96
+ None, "--prompt", "-p", help="The prompt to send to the chat service."
97
+ ),
98
+ model: str = typer.Option(None, "--model", "-m", help="The model to use for the chat service."),
99
+ response_format: ChatFormat = typer.Option(
100
+ ChatFormat.text, "--format", "-f", help="The format of the response."
101
+ ),
102
+ stream: bool = typer.Option(False, "--stream", "-s", help="Stream the response."),
103
+ list_models: bool = typer.Option(
104
+ False, "--list-models", "-l", help="List available chat models."
105
+ ),
106
+ ):
107
+ """
108
+ Interact with qBraid AI chat service.
109
+
110
+ """
111
+ if list_models:
112
+ list_models_callback()
113
+ elif prompt:
114
+ prompt_callback(prompt, model, response_format, stream)
115
+ else:
116
+ raise click.UsageError(
117
+ "Invalid command. Please provide a prompt using --prompt "
118
+ "or use --list-models to view available models."
119
+ )
120
+
121
+
90
122
  if __name__ == "__main__":
91
123
  app()
@@ -16,8 +16,7 @@ from qbraid_core.system.executables import get_active_python_path
16
16
  from qbraid_cli.handlers import handle_error
17
17
  from qbraid_cli.pip.hooks import get_env_cfg_path, safe_set_include_sys_packages
18
18
 
19
- # disable pretty_exceptions_show_locals to avoid printing sensative information in the traceback
20
- pip_app = typer.Typer(help="Run pip command in active qBraid environment.")
19
+ pip_app = typer.Typer(help="Run pip command in active qBraid environment.", no_args_is_help=True)
21
20
 
22
21
 
23
22
  @pip_app.command(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: qbraid-cli
3
- Version: 0.9.0a0
3
+ Version: 0.9.2
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
  License-File: LICENSE
30
30
  Requires-Dist: typer>=0.12.1
31
31
  Requires-Dist: rich>=10.11.0
32
- Requires-Dist: qbraid-core>=0.1.28
32
+ Requires-Dist: click
33
+ Requires-Dist: qbraid-core>=0.1.31
33
34
  Provides-Extra: jobs
34
35
  Requires-Dist: amazon-braket-sdk>=1.48.1; extra == "jobs"
35
36
  Provides-Extra: envs
@@ -11,6 +11,7 @@ pyproject.toml
11
11
  .github/ISSUE_TEMPLATE/bug_report.yml
12
12
  .github/ISSUE_TEMPLATE/feature_request.yml
13
13
  .github/workflows/bump-version.yml
14
+ .github/workflows/docs-pr.yml
14
15
  .github/workflows/docs.yml
15
16
  .github/workflows/format.yml
16
17
  .github/workflows/main.yml
@@ -44,6 +45,8 @@ qbraid_cli/admin/__init__.py
44
45
  qbraid_cli/admin/app.py
45
46
  qbraid_cli/admin/headers.py
46
47
  qbraid_cli/admin/validation.py
48
+ qbraid_cli/chat/__init__.py
49
+ qbraid_cli/chat/app.py
47
50
  qbraid_cli/configure/__init__.py
48
51
  qbraid_cli/configure/actions.py
49
52
  qbraid_cli/configure/app.py
@@ -65,6 +68,7 @@ qbraid_cli/pip/__init__.py
65
68
  qbraid_cli/pip/app.py
66
69
  qbraid_cli/pip/hooks.py
67
70
  tests/__init__.py
71
+ tests/conftest.py
68
72
  tests/account/__init__.py
69
73
  tests/account/test_account_credits.py
70
74
  tests/admin/test_headers.py
@@ -1,6 +1,7 @@
1
1
  typer>=0.12.1
2
2
  rich>=10.11.0
3
- qbraid-core>=0.1.28
3
+ click
4
+ qbraid-core>=0.1.31
4
5
 
5
6
  [dev]
6
7
  isort
@@ -0,0 +1,35 @@
1
+ # Copyright (c) 2024, qBraid Development Team
2
+ # All rights reserved.
3
+
4
+ """
5
+ Configurations for pytest including remote test marker and command-line option.
6
+
7
+ """
8
+ import os
9
+
10
+ import pytest
11
+
12
+
13
+ def pytest_addoption(parser):
14
+ """Adds custom remote testing command-line option to pytest."""
15
+ parser.addoption(
16
+ "--remote",
17
+ action="store",
18
+ default=None,
19
+ help="Run tests that interface with remote, credentialed services: true or false",
20
+ )
21
+
22
+
23
+ def pytest_collection_modifyitems(config, items):
24
+ """Skip tests marked with `remote` if remote tests are disabled."""
25
+ remote_option = config.getoption("--remote")
26
+ if remote_option is None:
27
+ remote_option = os.getenv("QBRAID_RUN_REMOTE_TESTS", "True").lower() == "true"
28
+ else:
29
+ remote_option = remote_option.lower() == "true"
30
+
31
+ if not remote_option:
32
+ skip_remote = pytest.mark.skip(reason="Remote tests are disabled.")
33
+ for item in items:
34
+ if "remote" in item.keywords:
35
+ item.add_marker(skip_remote)
@@ -6,27 +6,20 @@ Unit tests for the devices_list function in the devices app.
6
6
 
7
7
  """
8
8
 
9
- import os
10
9
  from unittest.mock import MagicMock, patch
11
10
 
12
11
  import pytest
13
- from qbraid_core import QbraidSession
14
12
  from qbraid_core.services.quantum.exceptions import QuantumServiceRequestError
15
13
  from typer.testing import CliRunner
16
14
 
17
15
  from qbraid_cli.devices.app import devices_list
18
16
 
19
- qbraidrc_path = os.path.join(os.path.expanduser("~"), ".qbraid", "qbraidrc")
20
- qbraid_api_key = os.getenv("QBRAID_API_KEY")
21
-
22
17
  runner = CliRunner()
23
18
 
24
19
 
20
+ @pytest.mark.remote
25
21
  def test_devices_list_no_results():
26
22
  """Test when no results are returned from the API."""
27
- session = QbraidSession(api_key=qbraid_api_key)
28
- session.save_config(api_key=qbraid_api_key)
29
-
30
23
  with (
31
24
  patch("qbraid_core.services.quantum.process_job_data", return_value=([], 0)),
32
25
  patch("rich.console.Console.print") as mock_console_print,
@@ -35,6 +28,7 @@ def test_devices_list_no_results():
35
28
  assert "No results matching given criteria" in str(mock_console_print.call_args)
36
29
 
37
30
 
31
+ @pytest.mark.remote
38
32
  def test_quantum_client_search_devices_failure():
39
33
  """Test that QuantumClient.search_devices correctly raises an exception."""
40
34
  with patch(
@@ -44,16 +38,12 @@ def test_quantum_client_search_devices_failure():
44
38
  with pytest.raises(QuantumServiceRequestError) as exc_info:
45
39
  devices_list()
46
40
 
47
- # Assert the expected exception message
48
41
  assert str(exc_info.value) == "Failed to fetch device data"
49
42
 
50
43
 
44
+ @pytest.mark.remote
51
45
  def test_devices_list_error_handling():
52
46
  """Test error handling when an error occurs during device data retrieval."""
53
- # Setup the initial session configuration
54
- session = QbraidSession(api_key=qbraid_api_key)
55
- session.save_config(api_key=qbraid_api_key)
56
-
57
47
  with (
58
48
  patch("qbraid_cli.handlers.run_progress_task", return_value=(MagicMock(), MagicMock())),
59
49
  patch(
@@ -67,11 +57,9 @@ def test_devices_list_error_handling():
67
57
  assert str(exc_info.value) == "Failed to fetch device data."
68
58
 
69
59
 
60
+ @pytest.mark.remote
70
61
  def test_output_formatting_console():
71
62
  """Test the output formatting in the console."""
72
- session = QbraidSession(api_key=qbraid_api_key)
73
- session.save_config(api_key=qbraid_api_key)
74
-
75
63
  mock_device_data = [("AWS", "Quantum Computer", "dev_123", "ONLINE")]
76
64
 
77
65
  with (
@@ -6,22 +6,16 @@ Unit tests for the `jobs_list` function in the `qbraid_cli.jobs.app` module.
6
6
 
7
7
  """
8
8
 
9
- import os
10
9
  from unittest.mock import patch
11
10
 
12
- from qbraid_core import QbraidSession
11
+ import pytest
13
12
 
14
13
  from qbraid_cli.jobs.app import jobs_list
15
14
 
16
- qbraidrc_path = os.path.join(os.path.expanduser("~"), ".qbraid", "qbraidrc")
17
- qbraid_api_key = os.getenv("QBRAID_API_KEY")
18
-
19
15
 
16
+ @pytest.mark.remote
20
17
  def test_jobs_list_with_limit():
21
18
  """Test the `jobs_list` function with a limit parameter."""
22
- session = QbraidSession(api_key=qbraid_api_key)
23
- session.save_config(api_key=qbraid_api_key)
24
-
25
19
  mock_raw_data = [
26
20
  ("job_id_1", "2023-03-19 12:00", "COMPLETED"),
27
21
  ("job_id_2", "2023-03-18 11:00", "FAILED"),
@@ -41,11 +35,9 @@ def test_jobs_list_with_limit():
41
35
  ), "Console should print each job and possibly more for headers/executable."
42
36
 
43
37
 
38
+ @pytest.mark.remote
44
39
  def test_jobs_list_output_formatting_console():
45
40
  """Test the jobs list output formatting in the console."""
46
- session = QbraidSession(api_key=qbraid_api_key)
47
- session.save_config(api_key=qbraid_api_key)
48
-
49
41
  mock_raw_data = [("job_id_1", "2023-03-19 12:00", "COMPLETED")]
50
42
  mock_message = f"Displaying {len(mock_raw_data)} most recent jobs"
51
43
  mock_job_data = (mock_raw_data, mock_message)
@@ -55,6 +47,4 @@ def test_jobs_list_output_formatting_console():
55
47
  patch("rich.console.Console.print") as mock_console_print,
56
48
  ):
57
49
  jobs_list(limit=1)
58
-
59
- # Assuming here that if `Console.print` is called, formatting has been attempted
60
50
  mock_console_print.assert_called()
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes