qbraid-cli 0.8.0.dev0__py3-none-any.whl → 0.9.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of qbraid-cli might be problematic. Click here for more details.
- qbraid_cli/_version.py +2 -2
- qbraid_cli/account/__init__.py +11 -0
- qbraid_cli/account/app.py +65 -0
- qbraid_cli/admin/__init__.py +11 -0
- qbraid_cli/admin/app.py +59 -0
- qbraid_cli/admin/headers.py +235 -0
- qbraid_cli/admin/validation.py +32 -0
- qbraid_cli/chat/__init__.py +11 -0
- qbraid_cli/chat/app.py +76 -0
- qbraid_cli/configure/__init__.py +6 -1
- qbraid_cli/configure/actions.py +111 -0
- qbraid_cli/configure/app.py +34 -109
- qbraid_cli/devices/__init__.py +6 -1
- qbraid_cli/devices/app.py +43 -35
- qbraid_cli/devices/validation.py +26 -0
- qbraid_cli/envs/__init__.py +6 -1
- qbraid_cli/envs/activate.py +8 -5
- qbraid_cli/envs/app.py +215 -131
- qbraid_cli/envs/create.py +14 -120
- qbraid_cli/envs/data_handling.py +46 -0
- qbraid_cli/exceptions.py +3 -0
- qbraid_cli/files/__init__.py +11 -0
- qbraid_cli/files/app.py +118 -0
- qbraid_cli/handlers.py +47 -13
- qbraid_cli/jobs/__init__.py +6 -1
- qbraid_cli/jobs/app.py +84 -97
- qbraid_cli/jobs/toggle_braket.py +68 -74
- qbraid_cli/jobs/validation.py +94 -0
- qbraid_cli/kernels/__init__.py +6 -1
- qbraid_cli/kernels/app.py +81 -11
- qbraid_cli/main.py +66 -14
- qbraid_cli/pip/__init__.py +11 -0
- qbraid_cli/pip/app.py +50 -0
- qbraid_cli/pip/hooks.py +74 -0
- qbraid_cli/py.typed +0 -0
- qbraid_cli-0.9.5.dist-info/LICENSE +41 -0
- qbraid_cli-0.9.5.dist-info/METADATA +179 -0
- qbraid_cli-0.9.5.dist-info/RECORD +42 -0
- {qbraid_cli-0.8.0.dev0.dist-info → qbraid_cli-0.9.5.dist-info}/WHEEL +1 -1
- qbraid_cli/credits/__init__.py +0 -6
- qbraid_cli/credits/app.py +0 -30
- qbraid_cli-0.8.0.dev0.dist-info/METADATA +0 -124
- qbraid_cli-0.8.0.dev0.dist-info/RECORD +0 -25
- {qbraid_cli-0.8.0.dev0.dist-info → qbraid_cli-0.9.5.dist-info}/entry_points.txt +0 -0
- {qbraid_cli-0.8.0.dev0.dist-info → qbraid_cli-0.9.5.dist-info}/top_level.txt +0 -0
qbraid_cli/envs/app.py
CHANGED
|
@@ -1,180 +1,256 @@
|
|
|
1
|
+
# Copyright (c) 2024, qBraid Development Team
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
|
|
1
4
|
"""
|
|
2
5
|
Module defining commands in the 'qbraid envs' namespace.
|
|
3
6
|
|
|
4
7
|
"""
|
|
5
8
|
|
|
6
|
-
import json
|
|
7
9
|
import shutil
|
|
10
|
+
import subprocess
|
|
8
11
|
import sys
|
|
9
12
|
from pathlib import Path
|
|
10
|
-
from typing import
|
|
13
|
+
from typing import TYPE_CHECKING, Optional
|
|
11
14
|
|
|
12
15
|
import typer
|
|
16
|
+
from qbraid_core.services.environments.schema import EnvironmentConfig
|
|
13
17
|
from rich.console import Console
|
|
14
18
|
|
|
15
|
-
from qbraid_cli.
|
|
19
|
+
from qbraid_cli.envs.create import create_qbraid_env_assets, create_venv
|
|
20
|
+
from qbraid_cli.envs.data_handling import get_envs_data as installed_envs_data
|
|
21
|
+
from qbraid_cli.envs.data_handling import validate_env_name
|
|
22
|
+
from qbraid_cli.handlers import QbraidException, handle_error, run_progress_task
|
|
16
23
|
|
|
17
|
-
|
|
24
|
+
if TYPE_CHECKING:
|
|
25
|
+
from qbraid_core.services.environments.client import EnvironmentManagerClient as EMC
|
|
18
26
|
|
|
27
|
+
envs_app = typer.Typer(help="Manage qBraid environments.", no_args_is_help=True)
|
|
19
28
|
|
|
20
|
-
def installed_envs_data() -> Tuple[Dict[str, Path], Dict[str, str]]:
|
|
21
|
-
"""Gather paths and aliases for all installed qBraid environments."""
|
|
22
|
-
from qbraid.api.system import get_qbraid_envs_paths, is_valid_slug
|
|
23
29
|
|
|
24
|
-
|
|
25
|
-
|
|
30
|
+
@envs_app.command(name="create")
|
|
31
|
+
def envs_create( # pylint: disable=too-many-statements
|
|
32
|
+
name: str = typer.Option(None, "--name", "-n", help="Name of the environment to create"),
|
|
33
|
+
description: Optional[str] = typer.Option(
|
|
34
|
+
None, "--description", "-d", help="Short description of the environment"
|
|
35
|
+
),
|
|
36
|
+
file_path: str = typer.Option(
|
|
37
|
+
None, "--file", "-f", help="Path to a .yml file containing the environment details"
|
|
38
|
+
),
|
|
39
|
+
auto_confirm: bool = typer.Option(
|
|
40
|
+
False, "--yes", "-y", help="Automatically answer 'yes' to all prompts"
|
|
41
|
+
),
|
|
42
|
+
) -> None:
|
|
43
|
+
"""Create a new qBraid environment."""
|
|
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))
|
|
26
74
|
|
|
27
|
-
|
|
75
|
+
if not name:
|
|
76
|
+
name = custom_env_data.name
|
|
28
77
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
installed[entry.name] = entry
|
|
78
|
+
def create_environment(*args, **kwargs) -> "tuple[dict, EMC]":
|
|
79
|
+
"""Create a qBraid environment."""
|
|
80
|
+
from qbraid_core.services.environments.client import EnvironmentManagerClient
|
|
33
81
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
continue
|
|
82
|
+
client = EnvironmentManagerClient()
|
|
83
|
+
return client.create_environment(*args, **kwargs), client
|
|
37
84
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
with open(state_json_path, "r", encoding="utf-8") as f:
|
|
42
|
-
data = json.load(f)
|
|
43
|
-
aliases[data.get("name", entry.name[:-7])] = entry.name
|
|
44
|
-
# pylint: disable-next=broad-exception-caught
|
|
45
|
-
except (json.JSONDecodeError, Exception):
|
|
46
|
-
aliases[entry.name[:-7]] = entry.name
|
|
47
|
-
else:
|
|
48
|
-
aliases[entry.name[:-7]] = entry.name
|
|
85
|
+
def gather_local_data() -> tuple[Path, str]:
|
|
86
|
+
"""Gather environment data and return the slug."""
|
|
87
|
+
from qbraid_core.services.environments import get_default_envs_paths
|
|
49
88
|
|
|
50
|
-
|
|
89
|
+
env_path = get_default_envs_paths()[0]
|
|
51
90
|
|
|
91
|
+
result = subprocess.run(
|
|
92
|
+
[sys.executable, "--version"],
|
|
93
|
+
capture_output=True,
|
|
94
|
+
text=True,
|
|
95
|
+
check=True,
|
|
96
|
+
)
|
|
52
97
|
|
|
53
|
-
|
|
54
|
-
def envs_create(
|
|
55
|
-
name: str = typer.Option(..., "--name", "-n", help="Name of the environment to create"),
|
|
56
|
-
description: Optional[str] = typer.Option(
|
|
57
|
-
None, "--description", "-d", help="Short description of the environment"
|
|
58
|
-
),
|
|
59
|
-
) -> None:
|
|
60
|
-
"""Create a new qBraid environment.
|
|
98
|
+
python_version = result.stdout or result.stderr
|
|
61
99
|
|
|
62
|
-
|
|
63
|
-
This command will not work until that PR is merged, and the updates are deployed.
|
|
64
|
-
"""
|
|
65
|
-
from .create import create_qbraid_env
|
|
100
|
+
return env_path, python_version
|
|
66
101
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
102
|
+
if not custom_env_data:
|
|
103
|
+
custom_env_data = EnvironmentConfig(
|
|
104
|
+
name=name,
|
|
105
|
+
description=env_description,
|
|
106
|
+
)
|
|
70
107
|
|
|
71
|
-
|
|
108
|
+
environment, emc = run_progress_task(
|
|
109
|
+
create_environment,
|
|
110
|
+
custom_env_data,
|
|
111
|
+
description="Validating request...",
|
|
112
|
+
error_message="Failed to create qBraid environment",
|
|
113
|
+
)
|
|
72
114
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
raise QbraidException("Create environment request failed") from err
|
|
77
|
-
|
|
78
|
-
slug = resp.get("slug")
|
|
79
|
-
if slug is None:
|
|
80
|
-
raise QbraidException(f"Create environment request returned invalid slug, {slug}")
|
|
81
|
-
|
|
82
|
-
return slug
|
|
83
|
-
|
|
84
|
-
req_body = {
|
|
85
|
-
"name": name,
|
|
86
|
-
"description": description or "",
|
|
87
|
-
"tags": "", # comma separated list of tags
|
|
88
|
-
"code": "", # newline separated list of packages
|
|
89
|
-
"visibility": "private",
|
|
90
|
-
"kernelName": "",
|
|
91
|
-
"prompt": "",
|
|
92
|
-
}
|
|
93
|
-
slug = run_progress_task(
|
|
94
|
-
request_new_env,
|
|
95
|
-
req_body,
|
|
96
|
-
description="Validating...",
|
|
115
|
+
env_path, python_version = run_progress_task(
|
|
116
|
+
gather_local_data,
|
|
117
|
+
description="Solving environment...",
|
|
97
118
|
error_message="Failed to create qBraid environment",
|
|
98
119
|
)
|
|
99
120
|
|
|
121
|
+
slug = environment.get("slug")
|
|
122
|
+
display_name = environment.get("displayName")
|
|
123
|
+
prompt = environment.get("prompt")
|
|
124
|
+
description = environment.get("description")
|
|
125
|
+
tags = environment.get("tags")
|
|
126
|
+
kernel_name = environment.get("kernelName")
|
|
127
|
+
|
|
128
|
+
slug_path = env_path / slug
|
|
129
|
+
description = "None" if description == "" else description
|
|
130
|
+
|
|
131
|
+
typer.echo("## qBraid Metadata ##\n")
|
|
132
|
+
typer.echo(f" name: {display_name}")
|
|
133
|
+
typer.echo(f" description: {description}")
|
|
134
|
+
typer.echo(f" tags: {tags}")
|
|
135
|
+
typer.echo(f" slug: {slug}")
|
|
136
|
+
typer.echo(f" shellPrompt: {prompt}")
|
|
137
|
+
typer.echo(f" kernelName: {kernel_name}")
|
|
138
|
+
|
|
139
|
+
typer.echo("\n\n## Environment Plan ##\n")
|
|
140
|
+
typer.echo(f" location: {slug_path}")
|
|
141
|
+
typer.echo(f" version: {python_version}\n")
|
|
142
|
+
|
|
143
|
+
user_confirmation = auto_confirm or typer.confirm("Proceed", default=True)
|
|
144
|
+
typer.echo("")
|
|
145
|
+
if not user_confirmation:
|
|
146
|
+
emc.delete_environment(slug)
|
|
147
|
+
typer.echo("qBraidSystemExit: Exiting.")
|
|
148
|
+
raise typer.Exit()
|
|
149
|
+
|
|
100
150
|
run_progress_task(
|
|
101
|
-
|
|
151
|
+
create_qbraid_env_assets,
|
|
102
152
|
slug,
|
|
103
|
-
|
|
104
|
-
|
|
153
|
+
prompt,
|
|
154
|
+
kernel_name,
|
|
155
|
+
slug_path,
|
|
156
|
+
description="Generating qBraid assets...",
|
|
157
|
+
error_message="Failed to create qBraid environment",
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
run_progress_task(
|
|
161
|
+
create_venv,
|
|
162
|
+
slug_path,
|
|
163
|
+
prompt,
|
|
164
|
+
description="Creating virtual environment...",
|
|
105
165
|
error_message="Failed to create qBraid environment",
|
|
106
166
|
)
|
|
107
167
|
|
|
108
|
-
# TODO: Add the command they can use to activate the environment to end of success message
|
|
109
168
|
console = Console()
|
|
110
169
|
console.print(
|
|
111
|
-
f"
|
|
170
|
+
f"[bold green]Successfully created qBraid environment: "
|
|
112
171
|
f"[/bold green][bold magenta]{name}[/bold magenta]\n"
|
|
113
172
|
)
|
|
173
|
+
typer.echo("# To activate this environment, use")
|
|
174
|
+
typer.echo("#")
|
|
175
|
+
typer.echo(f"# $ qbraid envs activate {name}")
|
|
176
|
+
typer.echo("#")
|
|
177
|
+
typer.echo("# To deactivate an active environment, use")
|
|
178
|
+
typer.echo("#")
|
|
179
|
+
typer.echo("# $ deactivate")
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
@envs_app.command(name="remove")
|
|
183
|
+
def envs_remove(
|
|
184
|
+
name: str = typer.Option(..., "-n", "--name", help="Name of the environment to remove"),
|
|
185
|
+
auto_confirm: bool = typer.Option(
|
|
186
|
+
False, "--yes", "-y", help="Automatically answer 'yes' to all prompts"
|
|
187
|
+
),
|
|
188
|
+
) -> None:
|
|
189
|
+
"""Delete a qBraid environment."""
|
|
114
190
|
|
|
191
|
+
def delete_environment(slug: str) -> None:
|
|
192
|
+
"""Delete a qBraid environment."""
|
|
193
|
+
from qbraid_core.services.environments.client import EnvironmentManagerClient
|
|
115
194
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
"""Delete a qBraid environment.
|
|
119
|
-
|
|
120
|
-
NOTE: Requires updated API route from https://github.com/qBraid/api/pull/482,
|
|
121
|
-
This command will not work until that PR is merged, and the updates are deployed.
|
|
122
|
-
"""
|
|
123
|
-
|
|
124
|
-
def request_delete_env(name: str) -> str:
|
|
125
|
-
"""Send request to create new environment and return the slug."""
|
|
126
|
-
from qbraid.api import QbraidSession, RequestsApiError
|
|
127
|
-
|
|
128
|
-
session = QbraidSession()
|
|
195
|
+
emc = EnvironmentManagerClient()
|
|
196
|
+
emc.delete_environment(slug)
|
|
129
197
|
|
|
198
|
+
def gather_local_data(env_name: str) -> tuple[Path, str]:
|
|
199
|
+
"""Get environment path and slug from name (alias)."""
|
|
130
200
|
installed, aliases = installed_envs_data()
|
|
131
|
-
for alias,
|
|
132
|
-
if alias ==
|
|
133
|
-
|
|
134
|
-
path = installed[slug_name]
|
|
135
|
-
|
|
136
|
-
try:
|
|
137
|
-
session.delete(f"/environments/{slug}")
|
|
138
|
-
except RequestsApiError as err:
|
|
139
|
-
raise QbraidException("Create environment request failed") from err
|
|
201
|
+
for alias, slug in aliases.items():
|
|
202
|
+
if alias == env_name:
|
|
203
|
+
path = installed[slug]
|
|
140
204
|
|
|
141
|
-
return path
|
|
205
|
+
return path, slug
|
|
142
206
|
|
|
143
207
|
raise QbraidException(f"Environment '{name}' not found.")
|
|
144
208
|
|
|
145
|
-
|
|
146
|
-
request_delete_env,
|
|
147
|
-
name,
|
|
148
|
-
description="Deleting remote environment data...",
|
|
149
|
-
error_message="Failed to delete qBraid environment",
|
|
150
|
-
)
|
|
209
|
+
slug_path, slug = gather_local_data(name)
|
|
151
210
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
console = Console()
|
|
160
|
-
console.print(
|
|
161
|
-
f"\n[bold green]Successfully delete qBraid environment: "
|
|
162
|
-
f"[/bold green][bold magenta]{name}[/bold magenta]\n"
|
|
211
|
+
confirmation_message = (
|
|
212
|
+
f"⚠️ Warning: You are about to delete the environment '{name}' "
|
|
213
|
+
f"located at '{slug_path}'.\n"
|
|
214
|
+
"This will remove all local packages and permanently delete all "
|
|
215
|
+
"of its associated qBraid environment metadata.\n"
|
|
216
|
+
"This operation CANNOT be undone.\n\n"
|
|
217
|
+
"Are you sure you want to continue?"
|
|
163
218
|
)
|
|
164
219
|
|
|
165
|
-
|
|
166
|
-
|
|
220
|
+
if auto_confirm or typer.confirm(confirmation_message, abort=True):
|
|
221
|
+
typer.echo("")
|
|
222
|
+
run_progress_task(
|
|
223
|
+
delete_environment,
|
|
224
|
+
slug,
|
|
225
|
+
description="Deleting remote environment data...",
|
|
226
|
+
error_message="Failed to delete qBraid environment",
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
run_progress_task(
|
|
230
|
+
shutil.rmtree,
|
|
231
|
+
slug_path,
|
|
232
|
+
description="Deleting local environment...",
|
|
233
|
+
error_message="Failed to delete qBraid environment",
|
|
234
|
+
)
|
|
235
|
+
typer.echo(f"Environment '{name}' successfully removed.")
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
@envs_app.command(name="list")
|
|
167
239
|
def envs_list():
|
|
168
240
|
"""List installed qBraid environments."""
|
|
169
241
|
installed, aliases = installed_envs_data()
|
|
170
242
|
|
|
243
|
+
console = Console()
|
|
244
|
+
|
|
171
245
|
if len(installed) == 0:
|
|
172
|
-
print(
|
|
173
|
-
|
|
246
|
+
console.print(
|
|
247
|
+
"No qBraid environments installed.\n\n"
|
|
248
|
+
+ "Use 'qbraid envs create' to create a new environment.",
|
|
249
|
+
style="yellow",
|
|
250
|
+
)
|
|
174
251
|
return
|
|
175
252
|
|
|
176
253
|
alias_path_pairs = [(alias, installed[slug_name]) for alias, slug_name in aliases.items()]
|
|
177
|
-
|
|
178
254
|
sorted_alias_path_pairs = sorted(
|
|
179
255
|
alias_path_pairs,
|
|
180
256
|
key=lambda x: (x[0] != "default", str(x[1]).startswith(str(Path.home())), x[0]),
|
|
@@ -183,23 +259,31 @@ def envs_list():
|
|
|
183
259
|
current_env_path = Path(sys.executable).parent.parent.parent
|
|
184
260
|
|
|
185
261
|
max_alias_length = (
|
|
186
|
-
max(len(alias) for alias,
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
max(len(str(path)) for _, path in sorted_alias_path_pairs) if sorted_alias_path_pairs else 0
|
|
262
|
+
max(len(str(alias)) for alias, envpath in sorted_alias_path_pairs)
|
|
263
|
+
if sorted_alias_path_pairs
|
|
264
|
+
else 0
|
|
190
265
|
)
|
|
191
266
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
267
|
+
output_lines = []
|
|
268
|
+
output_lines.append("# qbraid environments:")
|
|
269
|
+
output_lines.append("#")
|
|
270
|
+
output_lines.append("")
|
|
271
|
+
|
|
195
272
|
for alias, path in sorted_alias_path_pairs:
|
|
196
|
-
mark = "*
|
|
197
|
-
|
|
273
|
+
mark = "*" if path == current_env_path else " "
|
|
274
|
+
line = f"{alias.ljust(max_alias_length + 3)}{mark} {path}"
|
|
275
|
+
output_lines.append(line)
|
|
276
|
+
|
|
277
|
+
final_output = "\n".join(output_lines)
|
|
198
278
|
|
|
279
|
+
console.print(final_output)
|
|
199
280
|
|
|
200
|
-
|
|
281
|
+
|
|
282
|
+
@envs_app.command(name="activate")
|
|
201
283
|
def envs_activate(
|
|
202
|
-
name: str = typer.Argument(
|
|
284
|
+
name: str = typer.Argument(
|
|
285
|
+
..., help="Name of the environment. Values from 'qbraid envs list'."
|
|
286
|
+
),
|
|
203
287
|
):
|
|
204
288
|
"""Activate qBraid environment.
|
|
205
289
|
|
|
@@ -219,4 +303,4 @@ def envs_activate(
|
|
|
219
303
|
|
|
220
304
|
|
|
221
305
|
if __name__ == "__main__":
|
|
222
|
-
|
|
306
|
+
envs_app()
|
qbraid_cli/envs/create.py
CHANGED
|
@@ -1,135 +1,29 @@
|
|
|
1
|
+
# Copyright (c) 2024, qBraid Development Team
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
|
|
1
4
|
"""
|
|
2
5
|
Module supporting 'qbraid envs create' command.
|
|
3
6
|
|
|
4
7
|
"""
|
|
5
8
|
|
|
6
|
-
import json
|
|
7
|
-
import os
|
|
8
|
-
import shutil
|
|
9
|
-
import subprocess
|
|
10
|
-
import sys
|
|
11
|
-
from typing import Optional
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
def create_alias(slug: str) -> str:
|
|
15
|
-
"""Create an alias from a slug."""
|
|
16
|
-
return slug[:-7].replace("_", "-").strip("-")
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def replace_str(target: str, replacement: str, file_path: str) -> None:
|
|
20
|
-
"""Replace all instances of string in file"""
|
|
21
|
-
with open(file_path, "r", encoding="utf-8") as file:
|
|
22
|
-
content = file.read()
|
|
23
|
-
|
|
24
|
-
content = content.replace(target, replacement)
|
|
25
|
-
|
|
26
|
-
with open(file_path, "w", encoding="utf-8") as file:
|
|
27
|
-
file.write(content)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
def update_state_json(
|
|
31
|
-
slug_path: str,
|
|
32
|
-
install_complete: int,
|
|
33
|
-
install_success: int,
|
|
34
|
-
message: Optional[str] = None,
|
|
35
|
-
env_name: Optional[str] = None,
|
|
36
|
-
) -> None:
|
|
37
|
-
"""Update environment's install status values in a JSON file.
|
|
38
|
-
Truth table values: 0 = False, 1 = True, -1 = Unknown
|
|
39
|
-
"""
|
|
40
|
-
# Set default message if none provided
|
|
41
|
-
message = "" if message is None else message.replace("\n", " ")
|
|
42
|
-
|
|
43
|
-
# File path for state.json
|
|
44
|
-
state_json_path = os.path.join(slug_path, "state.json")
|
|
45
9
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
data = json.load(f)
|
|
50
|
-
else:
|
|
51
|
-
data = {"install": {}}
|
|
10
|
+
def create_venv(*args, **kwargs) -> None:
|
|
11
|
+
"""Create a python virtual environment for the qBraid environment."""
|
|
12
|
+
from qbraid_core.services.environments import create_local_venv
|
|
52
13
|
|
|
53
|
-
|
|
54
|
-
data["install"]["complete"] = install_complete
|
|
55
|
-
data["install"]["success"] = install_success
|
|
56
|
-
data["install"]["message"] = message
|
|
14
|
+
return create_local_venv(*args, **kwargs)
|
|
57
15
|
|
|
58
|
-
if env_name is not None:
|
|
59
|
-
data["name"] = env_name.lower()
|
|
60
16
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
17
|
+
def update_state_json(*ags, **kwargs) -> None:
|
|
18
|
+
"""Update the state.json file for the qBraid environment."""
|
|
19
|
+
from qbraid_core.services.environments.state import update_state_json as update_state
|
|
64
20
|
|
|
21
|
+
return update_state(*ags, **kwargs)
|
|
65
22
|
|
|
66
|
-
def create_venv(slug_path: str, prompt: str) -> None:
|
|
67
|
-
"""Create virtual environment and swap PS1 display name."""
|
|
68
|
-
venv_path = os.path.join(slug_path, "pyenv")
|
|
69
|
-
subprocess.run([sys.executable, "-m", "venv", venv_path], check=True)
|
|
70
23
|
|
|
71
|
-
|
|
72
|
-
if sys.platform == "win32":
|
|
73
|
-
scripts_path = os.path.join(venv_path, "Scripts")
|
|
74
|
-
activate_files = ["activate.bat", "Activate.ps1"]
|
|
75
|
-
else:
|
|
76
|
-
scripts_path = os.path.join(venv_path, "bin")
|
|
77
|
-
activate_files = ["activate", "activate.csh", "activate.fish"]
|
|
78
|
-
|
|
79
|
-
for file in activate_files:
|
|
80
|
-
file_path = os.path.join(scripts_path, file)
|
|
81
|
-
if os.path.isfile(file_path):
|
|
82
|
-
replace_str("(pyenv)", f"({prompt})", file_path)
|
|
83
|
-
|
|
84
|
-
replace_str(
|
|
85
|
-
"include-system-site-packages = false",
|
|
86
|
-
"include-system-site-packages = true",
|
|
87
|
-
os.path.join(venv_path, "pyvenv.cfg"),
|
|
88
|
-
)
|
|
89
|
-
|
|
90
|
-
update_state_json(slug_path, 1, 1)
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
def create_qbraid_env(slug: str, name: str) -> None:
|
|
24
|
+
def create_qbraid_env_assets(slug: str, alias: str, kernel_name: str, slug_path: str) -> None:
|
|
94
25
|
"""Create a qBraid environment including python venv, PS1 configs,
|
|
95
26
|
kernel resource files, and qBraid state.json."""
|
|
96
|
-
|
|
97
|
-
from jupyter_client.kernelspec import KernelSpecManager
|
|
98
|
-
from qbraid.api.system import get_qbraid_envs_paths
|
|
99
|
-
|
|
100
|
-
alias = create_alias(slug)
|
|
101
|
-
display_name = f"Python 3 [{alias}]"
|
|
102
|
-
envs_dir_path = get_qbraid_envs_paths()[0]
|
|
103
|
-
slug_path = os.path.join(str(envs_dir_path), slug)
|
|
104
|
-
local_resource_dir = os.path.join(slug_path, "kernels", f"python3_{slug}")
|
|
105
|
-
os.makedirs(local_resource_dir, exist_ok=True)
|
|
106
|
-
|
|
107
|
-
# create state.json
|
|
108
|
-
update_state_json(slug_path, 0, 0, env_name=name)
|
|
109
|
-
|
|
110
|
-
# create kernel.json
|
|
111
|
-
kernel_json_path = os.path.join(local_resource_dir, "kernel.json")
|
|
112
|
-
kernel_spec_manager = KernelSpecManager()
|
|
113
|
-
kernelspec_dict = kernel_spec_manager.get_all_specs()
|
|
114
|
-
kernel_data = kernelspec_dict["python3"]["spec"]
|
|
115
|
-
if sys.platform == "win32":
|
|
116
|
-
python_exec_path = os.path.join(slug_path, "pyenv", "Scripts", "python.exe")
|
|
117
|
-
else:
|
|
118
|
-
python_exec_path = os.path.join(slug_path, "pyenv", "bin", "python")
|
|
119
|
-
kernel_data["argv"][0] = python_exec_path
|
|
120
|
-
kernel_data["display_name"] = display_name
|
|
121
|
-
with open(kernel_json_path, "w", encoding="utf-8") as file:
|
|
122
|
-
json.dump(kernel_data, file, indent=4)
|
|
123
|
-
|
|
124
|
-
# copy logo files
|
|
125
|
-
sys_resource_dir = kernelspec_dict["python3"]["resource_dir"]
|
|
126
|
-
logo_files = ["logo-32x32.png", "logo-64x64.png", "logo-svg.svg"]
|
|
127
|
-
|
|
128
|
-
for file in logo_files:
|
|
129
|
-
sys_path = os.path.join(sys_resource_dir, file)
|
|
130
|
-
loc_path = os.path.join(local_resource_dir, file)
|
|
131
|
-
if os.path.isfile(sys_path):
|
|
132
|
-
shutil.copy(sys_path, loc_path)
|
|
27
|
+
from qbraid_core.services.environments.create import create_qbraid_env_assets as create_assets
|
|
133
28
|
|
|
134
|
-
|
|
135
|
-
create_venv(slug_path, alias)
|
|
29
|
+
return create_assets(slug, alias, kernel_name, slug_path)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Copyright (c) 2024, qBraid Development Team
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
Module for handling data related to qBraid environments.
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import typer
|
|
10
|
+
|
|
11
|
+
from qbraid_cli.handlers import QbraidException
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def get_envs_data(*args, **kwargs) -> dict:
|
|
15
|
+
"""Get data for installed environments."""
|
|
16
|
+
from qbraid_core.services.environments.paths import installed_envs_data
|
|
17
|
+
|
|
18
|
+
return installed_envs_data(*args, **kwargs)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def is_valid_env_name(value: str) -> bool:
|
|
22
|
+
"""Check if a given string is a valid Python environment name."""
|
|
23
|
+
from qbraid_core.services.environments.validate import is_valid_env_name as is_valid
|
|
24
|
+
|
|
25
|
+
return is_valid(value)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def validate_env_name(value: str) -> str:
|
|
29
|
+
"""Validate environment name."""
|
|
30
|
+
if not is_valid_env_name(value):
|
|
31
|
+
raise typer.BadParameter(
|
|
32
|
+
f"Invalid environment name '{value}'. " "Please use a valid Python environment name."
|
|
33
|
+
)
|
|
34
|
+
return value
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def request_delete_env(slug: str) -> str:
|
|
38
|
+
"""Send request to delete environment given slug."""
|
|
39
|
+
from qbraid_core import QbraidSession, RequestsApiError
|
|
40
|
+
|
|
41
|
+
session = QbraidSession()
|
|
42
|
+
|
|
43
|
+
try:
|
|
44
|
+
session.delete(f"/environments/{slug}")
|
|
45
|
+
except RequestsApiError as err:
|
|
46
|
+
raise QbraidException("Delete environment request failed") from err
|
qbraid_cli/exceptions.py
CHANGED