qbraid-cli 0.9.2__tar.gz → 0.9.4__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 (118) hide show
  1. {qbraid_cli-0.9.2/qbraid_cli.egg-info → qbraid_cli-0.9.4}/PKG-INFO +2 -2
  2. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/docs/index.rst +3 -2
  3. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/pyproject.toml +2 -2
  4. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/qbraid_cli/_version.py +2 -2
  5. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/qbraid_cli/envs/app.py +46 -6
  6. qbraid_cli-0.9.4/qbraid_cli/files/__init__.py +11 -0
  7. qbraid_cli-0.9.4/qbraid_cli/files/app.py +118 -0
  8. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/qbraid_cli/main.py +2 -0
  9. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4/qbraid_cli.egg-info}/PKG-INFO +2 -2
  10. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/qbraid_cli.egg-info/SOURCES.txt +8 -0
  11. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/qbraid_cli.egg-info/requires.txt +1 -1
  12. qbraid_cli-0.9.4/tests/envs/test_envs_create_from_yaml.py +108 -0
  13. qbraid_cli-0.9.4/tests/files/test_files_commands.py +109 -0
  14. qbraid_cli-0.9.4/tests/kernels/__init__.py +0 -0
  15. qbraid_cli-0.9.4/tests/resources/envs/correct.yaml +16 -0
  16. qbraid_cli-0.9.4/tests/resources/envs/icon.png +0 -0
  17. qbraid_cli-0.9.4/tests/resources/envs/incorrect.yaml +4 -0
  18. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/tools/split_md.py +2 -0
  19. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/.env.example +0 -0
  20. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  21. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  22. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  23. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/.github/workflows/bump-version.yml +0 -0
  24. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/.github/workflows/docs-pr.yml +0 -0
  25. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/.github/workflows/docs.yml +0 -0
  26. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/.github/workflows/format.yml +0 -0
  27. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/.github/workflows/main.yml +0 -0
  28. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/.github/workflows/pre-release.yml +0 -0
  29. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/.github/workflows/publish.yml +0 -0
  30. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/.github/workflows/tag-on-merge.yml +0 -0
  31. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/.gitignore +0 -0
  32. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/.readthedocs.yml +0 -0
  33. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/CONTRIBUTING.md +0 -0
  34. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/LICENSE +0 -0
  35. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/MANIFEST.IN +0 -0
  36. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/Makefile +0 -0
  37. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/README.md +0 -0
  38. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/docs/Makefile +0 -0
  39. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/docs/_static/favicon.ico +0 -0
  40. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/docs/_static/logo.png +0 -0
  41. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/docs/_static/style/custom.css +0 -0
  42. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/docs/_static/style/s4defs-roles.css +0 -0
  43. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/docs/conf.py +0 -0
  44. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/docs/make.bat +0 -0
  45. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/docs/requirements.txt +0 -0
  46. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/qbraid_cli/__init__.py +0 -0
  47. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/qbraid_cli/account/__init__.py +0 -0
  48. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/qbraid_cli/account/app.py +0 -0
  49. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/qbraid_cli/admin/__init__.py +0 -0
  50. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/qbraid_cli/admin/app.py +0 -0
  51. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/qbraid_cli/admin/headers.py +0 -0
  52. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/qbraid_cli/admin/validation.py +0 -0
  53. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/qbraid_cli/chat/__init__.py +0 -0
  54. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/qbraid_cli/chat/app.py +0 -0
  55. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/qbraid_cli/configure/__init__.py +0 -0
  56. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/qbraid_cli/configure/actions.py +0 -0
  57. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/qbraid_cli/configure/app.py +0 -0
  58. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/qbraid_cli/devices/__init__.py +0 -0
  59. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/qbraid_cli/devices/app.py +0 -0
  60. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/qbraid_cli/devices/validation.py +0 -0
  61. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/qbraid_cli/envs/__init__.py +0 -0
  62. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/qbraid_cli/envs/activate.py +0 -0
  63. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/qbraid_cli/envs/create.py +0 -0
  64. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/qbraid_cli/envs/data_handling.py +0 -0
  65. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/qbraid_cli/exceptions.py +0 -0
  66. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/qbraid_cli/handlers.py +0 -0
  67. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/qbraid_cli/jobs/__init__.py +0 -0
  68. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/qbraid_cli/jobs/app.py +0 -0
  69. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/qbraid_cli/jobs/toggle_braket.py +0 -0
  70. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/qbraid_cli/jobs/validation.py +0 -0
  71. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/qbraid_cli/kernels/__init__.py +0 -0
  72. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/qbraid_cli/kernels/app.py +0 -0
  73. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/qbraid_cli/pip/__init__.py +0 -0
  74. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/qbraid_cli/pip/app.py +0 -0
  75. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/qbraid_cli/pip/hooks.py +0 -0
  76. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/qbraid_cli/py.typed +0 -0
  77. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/qbraid_cli.egg-info/dependency_links.txt +0 -0
  78. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/qbraid_cli.egg-info/entry_points.txt +0 -0
  79. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/qbraid_cli.egg-info/top_level.txt +0 -0
  80. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/setup.cfg +0 -0
  81. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/tests/__init__.py +0 -0
  82. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/tests/account/__init__.py +0 -0
  83. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/tests/account/test_account_credits.py +0 -0
  84. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/tests/admin/test_headers.py +0 -0
  85. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/tests/configure/__init__.py +0 -0
  86. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/tests/configure/test_configure_prompt_for_config.py +0 -0
  87. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/tests/configure/test_configure_set.py +0 -0
  88. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/tests/configure/test_configure_validate_input.py +0 -0
  89. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/tests/conftest.py +0 -0
  90. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/tests/devices/__init__.py +0 -0
  91. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/tests/devices/test_devices_list.py +0 -0
  92. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/tests/devices/test_devices_validations.py +0 -0
  93. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/tests/envs/__init__.py +0 -0
  94. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/tests/envs/test_envs_activate.py +0 -0
  95. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/tests/envs/test_envs_activate_find_shell_rc.py +0 -0
  96. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/tests/envs/test_envs_activate_print_command.py +0 -0
  97. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/tests/envs/test_envs_activate_pyenv.py +0 -0
  98. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/tests/envs/test_envs_list.py +0 -0
  99. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/tests/envs/test_envs_remove.py +0 -0
  100. {qbraid_cli-0.9.2/tests/jobs → qbraid_cli-0.9.4/tests/files}/__init__.py +0 -0
  101. {qbraid_cli-0.9.2/tests/kernels → qbraid_cli-0.9.4/tests/jobs}/__init__.py +0 -0
  102. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/tests/jobs/test_jobs_disable.py +0 -0
  103. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/tests/jobs/test_jobs_enable.py +0 -0
  104. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/tests/jobs/test_jobs_list.py +0 -0
  105. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/tests/jobs/test_jobs_state.py +0 -0
  106. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/tests/jobs/test_jobs_toggle_braket_confirm.py +0 -0
  107. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/tests/jobs/test_jobs_toggle_braket_disable.py +0 -0
  108. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/tests/jobs/test_jobs_toggle_braket_enable.py +0 -0
  109. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/tests/jobs/test_jobs_toggle_braket_get_data.py +0 -0
  110. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/tests/jobs/test_jobs_validate_get_state.py +0 -0
  111. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/tests/jobs/test_jobs_validate_handle_state.py +0 -0
  112. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/tests/jobs/test_jobs_validate_library.py +0 -0
  113. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/tests/kernels/test_kernels_list.py +0 -0
  114. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/tools/bump_version.py +0 -0
  115. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/tools/create_dev_build.sh +0 -0
  116. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/tools/install_wheel_extras.sh +0 -0
  117. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/tools/split_rst.py +0 -0
  118. {qbraid_cli-0.9.2 → qbraid_cli-0.9.4}/tools/stamp_pre_release.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: qbraid-cli
3
- Version: 0.9.2
3
+ Version: 0.9.4
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
@@ -30,7 +30,7 @@ License-File: LICENSE
30
30
  Requires-Dist: typer>=0.12.1
31
31
  Requires-Dist: rich>=10.11.0
32
32
  Requires-Dist: click
33
- Requires-Dist: qbraid-core>=0.1.31
33
+ Requires-Dist: qbraid-core>=0.1.33
34
34
  Provides-Extra: jobs
35
35
  Requires-Dist: amazon-braket-sdk>=1.48.1; extra == "jobs"
36
36
  Provides-Extra: envs
@@ -6,7 +6,7 @@ Documentation
6
6
  <br />
7
7
 
8
8
  <h1 style="text-align: center">
9
- <img src="../_static/logo.png" alt="qbraid logo" style="width:50px;height:50px;">
9
+ <img src="_static/logo.png" alt="qbraid logo" style="width:50px;height:50px;">
10
10
  <span> qBraid</span>
11
11
  <span style="color:#808080"> | CLI</span>
12
12
  </h1>
@@ -121,4 +121,5 @@ by disabling quantum jobs:
121
121
  tree/qbraid_jobs
122
122
  tree/qbraid_kernels
123
123
  tree/qbraid_pip
124
- tree/qbraid_chat
124
+ tree/qbraid_chat
125
+ tree/qbraid_files
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "qbraid-cli"
7
- version = "0.9.2"
7
+ version = "0.9.4"
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" }]
@@ -31,7 +31,7 @@ dependencies = [
31
31
  "typer>=0.12.1",
32
32
  "rich>=10.11.0",
33
33
  "click",
34
- "qbraid-core>=0.1.31",
34
+ "qbraid-core>=0.1.33",
35
35
  ]
36
36
  requires-python = ">= 3.9"
37
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+gd39b277'
16
- __version_tuple__ = version_tuple = (0, 1, 'dev1', 'gd39b277')
15
+ __version__ = version = '0.1.dev1+gc0cd415'
16
+ __version_tuple__ = version_tuple = (0, 1, 'dev1', 'gc0cd415')
@@ -13,12 +13,13 @@ from pathlib import Path
13
13
  from typing import TYPE_CHECKING, Optional
14
14
 
15
15
  import typer
16
+ from qbraid_core.services.environments.schema import EnvironmentConfig
16
17
  from rich.console import Console
17
18
 
18
19
  from qbraid_cli.envs.create import create_qbraid_env_assets, create_venv
19
20
  from qbraid_cli.envs.data_handling import get_envs_data as installed_envs_data
20
21
  from qbraid_cli.envs.data_handling import validate_env_name
21
- from qbraid_cli.handlers import QbraidException, run_progress_task
22
+ from qbraid_cli.handlers import QbraidException, handle_error, run_progress_task
22
23
 
23
24
  if TYPE_CHECKING:
24
25
  from qbraid_core.services.environments.client import EnvironmentManagerClient as EMC
@@ -28,18 +29,51 @@ envs_app = typer.Typer(help="Manage qBraid environments.", no_args_is_help=True)
28
29
 
29
30
  @envs_app.command(name="create")
30
31
  def envs_create( # pylint: disable=too-many-statements
31
- name: str = typer.Option(
32
- ..., "--name", "-n", help="Name of the environment to create", callback=validate_env_name
33
- ),
32
+ name: str = typer.Option(None, "--name", "-n", help="Name of the environment to create"),
34
33
  description: Optional[str] = typer.Option(
35
34
  None, "--description", "-d", help="Short description of the environment"
36
35
  ),
36
+ file_path: str = typer.Option(
37
+ None, "--file", "-f", help="Path to a .yml file containing the environment details"
38
+ ),
37
39
  auto_confirm: bool = typer.Option(
38
40
  False, "--yes", "-y", help="Automatically answer 'yes' to all prompts"
39
41
  ),
40
42
  ) -> None:
41
43
  """Create a new qBraid environment."""
42
44
  env_description = description or ""
45
+ if name:
46
+ if not validate_env_name(name):
47
+ handle_error(
48
+ error_type="ValueError",
49
+ include_traceback=False,
50
+ message=f"Invalid environment name '{name}'. ",
51
+ )
52
+
53
+ env_details_in_cli = name is not None and env_description != ""
54
+ custom_env_data = None
55
+ if env_details_in_cli and file_path:
56
+ handle_error(
57
+ error_type="ArgumentConflictError",
58
+ include_traceback=False,
59
+ message="Cannot use --file with --name or --description while creating an environment",
60
+ )
61
+ elif not env_details_in_cli and not file_path:
62
+ handle_error(
63
+ error_type="MalformedCommandError",
64
+ include_traceback=False,
65
+ message="Must provide either --name and --description or --file "
66
+ "while creating an environment",
67
+ )
68
+ else:
69
+ try:
70
+ if file_path:
71
+ custom_env_data: EnvironmentConfig = EnvironmentConfig.from_yaml(file_path)
72
+ except ValueError as err:
73
+ handle_error(error_type="YamlValidationError", message=str(err))
74
+
75
+ if not name:
76
+ name = custom_env_data.name
43
77
 
44
78
  def create_environment(*args, **kwargs) -> "tuple[dict, EMC]":
45
79
  """Create a qBraid environment."""
@@ -65,10 +99,15 @@ def envs_create( # pylint: disable=too-many-statements
65
99
 
66
100
  return env_path, python_version
67
101
 
102
+ if not custom_env_data:
103
+ custom_env_data = EnvironmentConfig(
104
+ name=name,
105
+ description=env_description,
106
+ )
107
+
68
108
  environment, emc = run_progress_task(
69
109
  create_environment,
70
- name,
71
- env_description,
110
+ custom_env_data,
72
111
  description="Validating request...",
73
112
  error_message="Failed to create qBraid environment",
74
113
  )
@@ -78,6 +117,7 @@ def envs_create( # pylint: disable=too-many-statements
78
117
  description="Solving environment...",
79
118
  error_message="Failed to create qBraid environment",
80
119
  )
120
+
81
121
  slug = environment.get("slug")
82
122
  display_name = environment.get("displayName")
83
123
  prompt = environment.get("prompt")
@@ -0,0 +1,11 @@
1
+ # Copyright (c) 2024, qBraid Development Team
2
+ # All rights reserved.
3
+
4
+ """
5
+ Module defining the qbraid files namespace
6
+
7
+ """
8
+
9
+ from .app import files_app
10
+
11
+ __all__ = ["files_app"]
@@ -0,0 +1,118 @@
1
+ # Copyright (c) 2024, qBraid Development Team
2
+ # All rights reserved.
3
+
4
+ """
5
+ Module defining commands in the 'qbraid files' namespace.
6
+
7
+ """
8
+
9
+ from pathlib import Path
10
+ from typing import Any
11
+
12
+ import rich
13
+ import typer
14
+
15
+ from qbraid_cli.handlers import run_progress_task
16
+
17
+ files_app = typer.Typer(help="Manage qBraid cloud storage files.", no_args_is_help=True)
18
+
19
+
20
+ @files_app.command(name="upload")
21
+ def files_upload(
22
+ filepath: Path = typer.Argument(
23
+ ...,
24
+ exists=True,
25
+ dir_okay=False,
26
+ resolve_path=True,
27
+ help="Local path to the file to upload.",
28
+ ),
29
+ namespace: str = typer.Option(
30
+ "user",
31
+ "--namespace",
32
+ "-n",
33
+ help="Target qBraid namespace for the upload.",
34
+ ),
35
+ object_path: str = typer.Option(
36
+ None,
37
+ "--object-path",
38
+ "-p",
39
+ help=("Target object path. " "Defaults to original filename in namespace root."),
40
+ ),
41
+ overwrite: bool = typer.Option(
42
+ False,
43
+ "--overwrite",
44
+ "-o",
45
+ help="Overwrite existing file if it already exists in the target location.",
46
+ ),
47
+ ):
48
+ """Upload a local file to qBraid storage."""
49
+
50
+ def upload_file() -> dict[str, Any]:
51
+ from qbraid_core.services.files import FileManagerClient
52
+
53
+ client = FileManagerClient()
54
+ data = client.upload_file(
55
+ filepath, namespace=namespace, object_path=object_path, overwrite=overwrite
56
+ )
57
+ return data
58
+
59
+ data: dict = run_progress_task(
60
+ upload_file, description="Uploading file...", include_error_traceback=False
61
+ )
62
+
63
+ rich.print("File uploaded successfully!")
64
+ namespace = data.get("namespace")
65
+ object_path = data.get("objectPath")
66
+
67
+ if namespace and object_path:
68
+ rich.print(f"\nNamespace: '{namespace}'")
69
+ rich.print(f"Object path: '{object_path}'")
70
+
71
+
72
+ @files_app.command(name="download")
73
+ def files_download(
74
+ object_path: str = typer.Argument(
75
+ ...,
76
+ help="The folder + filename describing the file to download.",
77
+ ),
78
+ namespace: str = typer.Option(
79
+ "user",
80
+ "--namespace",
81
+ "-n",
82
+ help="Source qBraid namespace for the download.",
83
+ ),
84
+ save_path: Path = typer.Option(
85
+ Path.cwd(),
86
+ "--save-path",
87
+ "-s",
88
+ resolve_path=True,
89
+ help="Local directory to save the downloaded file.",
90
+ ),
91
+ overwrite: bool = typer.Option(
92
+ False,
93
+ "--overwrite",
94
+ "-o",
95
+ help="Overwrite existing file if it already exists in the target location.",
96
+ ),
97
+ ):
98
+ """Download a file from qBraid storage."""
99
+
100
+ def download_file() -> Path:
101
+ from qbraid_core.services.files import FileManagerClient
102
+
103
+ client = FileManagerClient()
104
+ file_path = client.download_file(
105
+ object_path, namespace=namespace, save_path=save_path, overwrite=overwrite
106
+ )
107
+ return file_path
108
+
109
+ file_path: Path = run_progress_task(
110
+ download_file, description="Downloading file...", include_error_traceback=False
111
+ )
112
+
113
+ rich.print("File downloaded successfully!")
114
+ rich.print(f"Saved to: '{str(file_path)}'")
115
+
116
+
117
+ if __name__ == "__main__":
118
+ files_app()
@@ -15,6 +15,7 @@ from qbraid_cli.admin import admin_app
15
15
  from qbraid_cli.chat import ChatFormat, list_models_callback, prompt_callback
16
16
  from qbraid_cli.configure import configure_app
17
17
  from qbraid_cli.devices import devices_app
18
+ from qbraid_cli.files import files_app
18
19
  from qbraid_cli.jobs import jobs_app
19
20
 
20
21
  try:
@@ -32,6 +33,7 @@ app.add_typer(admin_app, name="admin")
32
33
  app.add_typer(configure_app, name="configure")
33
34
  app.add_typer(account_app, name="account")
34
35
  app.add_typer(devices_app, name="devices")
36
+ app.add_typer(files_app, name="files")
35
37
  app.add_typer(jobs_app, name="jobs")
36
38
 
37
39
  if ENVS_COMMANDS is True:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: qbraid-cli
3
- Version: 0.9.2
3
+ Version: 0.9.4
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
@@ -30,7 +30,7 @@ License-File: LICENSE
30
30
  Requires-Dist: typer>=0.12.1
31
31
  Requires-Dist: rich>=10.11.0
32
32
  Requires-Dist: click
33
- Requires-Dist: qbraid-core>=0.1.31
33
+ Requires-Dist: qbraid-core>=0.1.33
34
34
  Provides-Extra: jobs
35
35
  Requires-Dist: amazon-braket-sdk>=1.48.1; extra == "jobs"
36
36
  Provides-Extra: envs
@@ -58,6 +58,8 @@ qbraid_cli/envs/activate.py
58
58
  qbraid_cli/envs/app.py
59
59
  qbraid_cli/envs/create.py
60
60
  qbraid_cli/envs/data_handling.py
61
+ qbraid_cli/files/__init__.py
62
+ qbraid_cli/files/app.py
61
63
  qbraid_cli/jobs/__init__.py
62
64
  qbraid_cli/jobs/app.py
63
65
  qbraid_cli/jobs/toggle_braket.py
@@ -84,8 +86,11 @@ tests/envs/test_envs_activate.py
84
86
  tests/envs/test_envs_activate_find_shell_rc.py
85
87
  tests/envs/test_envs_activate_print_command.py
86
88
  tests/envs/test_envs_activate_pyenv.py
89
+ tests/envs/test_envs_create_from_yaml.py
87
90
  tests/envs/test_envs_list.py
88
91
  tests/envs/test_envs_remove.py
92
+ tests/files/__init__.py
93
+ tests/files/test_files_commands.py
89
94
  tests/jobs/__init__.py
90
95
  tests/jobs/test_jobs_disable.py
91
96
  tests/jobs/test_jobs_enable.py
@@ -100,6 +105,9 @@ tests/jobs/test_jobs_validate_handle_state.py
100
105
  tests/jobs/test_jobs_validate_library.py
101
106
  tests/kernels/__init__.py
102
107
  tests/kernels/test_kernels_list.py
108
+ tests/resources/envs/correct.yaml
109
+ tests/resources/envs/icon.png
110
+ tests/resources/envs/incorrect.yaml
103
111
  tools/bump_version.py
104
112
  tools/create_dev_build.sh
105
113
  tools/install_wheel_extras.sh
@@ -1,7 +1,7 @@
1
1
  typer>=0.12.1
2
2
  rich>=10.11.0
3
3
  click
4
- qbraid-core>=0.1.31
4
+ qbraid-core>=0.1.33
5
5
 
6
6
  [dev]
7
7
  isort
@@ -0,0 +1,108 @@
1
+ # Copyright (c) 2024, qBraid Development Team
2
+ # All rights reserved.
3
+
4
+ """
5
+ Unit tests for the `qbraid_cli.envs.app` module's `activate` command.
6
+
7
+ """
8
+ from pathlib import Path
9
+ from unittest.mock import patch
10
+
11
+ from typer.testing import CliRunner
12
+
13
+ from qbraid_cli.envs.app import envs_app
14
+
15
+ runner = CliRunner(mix_stderr=False)
16
+
17
+ MOCK_API_RETURN_OBJ = {
18
+ "description": "This is a test qBraid environment for demonstration purposes.",
19
+ "logo": "test_s3_url",
20
+ "slug": "test_env_slug",
21
+ "displayName": "test_env",
22
+ "kernelName": "sample_kernel",
23
+ "name": "test_env",
24
+ "packagesInImage": {"numpy>=1.21.1", "openqasm3~=0.5.0", "qiskit", "cirq==1.0.0"},
25
+ "prompt": "sample_prompt",
26
+ "tags": ["test", "qbraid", "environment"],
27
+ }
28
+
29
+
30
+ def test_invalid_name_raises_error():
31
+ """Test that an invalid name raises an error."""
32
+ result = runner.invoke(
33
+ envs_app,
34
+ ["create", "--name", "invalid large name for environment", "--description", "test"],
35
+ )
36
+ assert result.exit_code == 2
37
+ assert "Invalid environment name " in result.stderr
38
+
39
+
40
+ # we mock the usage path of the method NOT its definition path
41
+ @patch("qbraid_cli.envs.app.run_progress_task")
42
+ def test_correct_yaml_parse(mock_run_progress_task):
43
+ """Test that the correct YAML file is parsed correctly."""
44
+
45
+ mock_run_progress_task.side_effect = [
46
+ (MOCK_API_RETURN_OBJ, None),
47
+ (Path("path/to/test_env"), "3.8"),
48
+ None,
49
+ None,
50
+ ]
51
+ yaml_file = "resources/envs/correct.yaml"
52
+ file_path = Path(__file__).resolve().parent.parent / yaml_file
53
+ result = runner.invoke(envs_app, ["create", "--file", file_path])
54
+ assert result.exit_code == 0
55
+ expected_outputs = [
56
+ "Successfully created qBraid environment: test_env",
57
+ "name: test_env",
58
+ "description: This is a test qBraid environment for demonstration purposes.",
59
+ "tags: ['test', 'qbraid', 'environment']",
60
+ "slug: test_env_slug",
61
+ "shellPrompt: sample_prompt",
62
+ "kernelName: sample_kernel",
63
+ f"location: {Path('path/to/test_env/test_env_slug')}",
64
+ "version: 3.8",
65
+ ]
66
+ for output in expected_outputs:
67
+ assert output in result.stdout
68
+
69
+
70
+ def test_invalid_yaml_file_raises_error():
71
+ """Test that an invalid YAML file raises an error."""
72
+ yaml_file = "resources/envs/incorrect.yaml"
73
+ file_path = Path(__file__).resolve().parent.parent / yaml_file
74
+ result = runner.invoke(envs_app, ["create", "--file", file_path])
75
+
76
+ assert result.exit_code == 1
77
+ assert "Invalid YAML data" in result.stderr
78
+
79
+
80
+ def test_no_name_no_file_raises_error():
81
+ """Test that providing neither a name nor a file raises an error."""
82
+ result = runner.invoke(envs_app, ["create"])
83
+ assert result.exit_code == 1
84
+ assert (
85
+ "Must provide either --name and --description or --file while creating an environment"
86
+ in result.stderr
87
+ )
88
+
89
+
90
+ def test_name_with_file_raises_error():
91
+ """Test that providing both a name and a file raises an error."""
92
+ result = runner.invoke(
93
+ envs_app,
94
+ [
95
+ "create",
96
+ "--name",
97
+ "test_env",
98
+ "--description",
99
+ "test",
100
+ "--file",
101
+ "resources/envs/correct.yaml",
102
+ ],
103
+ )
104
+ assert result.exit_code == 1
105
+ assert (
106
+ "Cannot use --file with --name or --description while creating an environment"
107
+ in result.stderr
108
+ )
@@ -0,0 +1,109 @@
1
+ # Copyright (c) 2024, qBraid Development Team
2
+ # All rights reserved.
3
+
4
+ # pylint: disable=redefined-outer-name
5
+
6
+ """
7
+ Unit tests for the `qbraid_cli.files.app` module.
8
+
9
+ """
10
+
11
+ from unittest.mock import patch
12
+
13
+ import pytest
14
+ from typer.testing import CliRunner
15
+
16
+ from qbraid_cli.files.app import files_app
17
+
18
+
19
+ @pytest.fixture
20
+ def runner():
21
+ """Fixture for invoking CLI commands."""
22
+ return CliRunner()
23
+
24
+
25
+ def test_files_upload(runner, tmp_path):
26
+ """Test the `files upload` command."""
27
+ test_file = tmp_path / "test_file.txt"
28
+ test_file.write_text("Test content")
29
+
30
+ with patch("qbraid_core.services.files.FileManagerClient") as mock_client:
31
+ mock_client.return_value.upload_file.return_value = {
32
+ "namespace": "user",
33
+ "objectPath": "test_file.txt",
34
+ }
35
+
36
+ result = runner.invoke(files_app, ["upload", str(test_file)])
37
+
38
+ assert result.exit_code == 0
39
+ assert "File uploaded successfully!" in result.stdout
40
+ assert "Namespace: 'user'" in result.stdout
41
+ assert "Object path: 'test_file.txt'" in result.stdout
42
+
43
+
44
+ def test_files_upload_with_options(runner, tmp_path):
45
+ """Test the `files upload` command with options."""
46
+ test_file = tmp_path / "test_file.txt"
47
+ test_file.write_text("Test content")
48
+
49
+ with patch("qbraid_core.services.files.FileManagerClient") as mock_client:
50
+ mock_client.return_value.upload_file.return_value = {
51
+ "namespace": "custom",
52
+ "objectPath": "folder/test_file.txt",
53
+ }
54
+
55
+ result = runner.invoke(
56
+ files_app,
57
+ [
58
+ "upload",
59
+ str(test_file),
60
+ "--namespace",
61
+ "custom",
62
+ "--object-path",
63
+ "folder/test_file.txt",
64
+ "--overwrite",
65
+ ],
66
+ )
67
+
68
+ assert result.exit_code == 0
69
+ assert "File uploaded successfully!" in result.stdout
70
+ assert "Namespace: 'custom'" in result.stdout
71
+ assert "Object path: 'folder/test_file.txt'" in result.stdout
72
+
73
+
74
+ def test_files_download(runner, tmp_path):
75
+ """Test the `files download` command."""
76
+ with patch("qbraid_core.services.files.FileManagerClient") as mock_client:
77
+ mock_client.return_value.download_file.return_value = tmp_path / "downloaded_file.txt"
78
+
79
+ result = runner.invoke(files_app, ["download", "test_file.txt"])
80
+
81
+ assert result.exit_code == 0
82
+ assert "File downloaded successfully!" in result.stdout
83
+ assert f"Saved to: '{(tmp_path / 'downloaded_file.txt')}'" in result.stdout.replace("\n", "")
84
+
85
+
86
+ def test_files_download_with_options(runner, tmp_path):
87
+ """Test the `files download` command with options."""
88
+ save_path = tmp_path / "custom_folder"
89
+ save_path.mkdir()
90
+
91
+ with patch("qbraid_core.services.files.FileManagerClient") as mock_client:
92
+ mock_client.return_value.download_file.return_value = save_path / "downloaded_file.txt"
93
+
94
+ result = runner.invoke(
95
+ files_app,
96
+ [
97
+ "download",
98
+ "folder/test_file.txt",
99
+ "--namespace",
100
+ "custom",
101
+ "--save-path",
102
+ str(save_path),
103
+ "--overwrite",
104
+ ],
105
+ )
106
+
107
+ assert result.exit_code == 0
108
+ assert "File downloaded successfully!" in result.stdout
109
+ assert f"Saved to: '{(save_path / 'downloaded_file.txt')}'" in result.stdout.replace("\n", "")
File without changes
@@ -0,0 +1,16 @@
1
+ # Sample qBraid environment configuration
2
+ name: "test_env"
3
+ description: "This is a test qBraid environment for demonstration purposes."
4
+ tags:
5
+ - "test"
6
+ - "qbraid"
7
+ - "environment"
8
+ icon: "tests/resources/envs/icon.png"
9
+ python_version: "3.8"
10
+ kernel_name: "sample_kernel"
11
+ shell_prompt: "sample_prompt"
12
+ python_packages:
13
+ numpy: ">=1.21.0"
14
+ openqasm3: "~=0.5.0"
15
+ qiskit: ""
16
+ cirq: "1.0.0"
@@ -0,0 +1,4 @@
1
+ # Sample qBraid environment configuration
2
+ name: "test_env"
3
+ description: "invalid"
4
+ backend: "qiskit"
@@ -137,6 +137,8 @@ def markdown_to_mdx(file_path: str) -> None:
137
137
  )
138
138
  continue
139
139
 
140
+ line = line.replace("&#x27;", "'")
141
+
140
142
  new_lines.append(line)
141
143
 
142
144
  # Construct the new file path with .mdx extension
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
File without changes
File without changes
File without changes
File without changes