qbraid-cli 0.8.0.dev1__py3-none-any.whl → 0.9.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of qbraid-cli might be problematic. Click here for more details.
- 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 +93 -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 +116 -197
- qbraid_cli/envs/create.py +13 -109
- 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 +46 -12
- qbraid_cli/jobs/__init__.py +6 -1
- qbraid_cli/jobs/app.py +76 -93
- 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 +74 -17
- 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.6.dist-info/LICENSE +41 -0
- qbraid_cli-0.9.6.dist-info/METADATA +179 -0
- qbraid_cli-0.9.6.dist-info/RECORD +42 -0
- {qbraid_cli-0.8.0.dev1.dist-info → qbraid_cli-0.9.6.dist-info}/WHEEL +1 -1
- qbraid_cli/credits/__init__.py +0 -6
- qbraid_cli/credits/app.py +0 -30
- qbraid_cli-0.8.0.dev1.dist-info/METADATA +0 -136
- qbraid_cli-0.8.0.dev1.dist-info/RECORD +0 -25
- {qbraid_cli-0.8.0.dev1.dist-info → qbraid_cli-0.9.6.dist-info}/entry_points.txt +0 -0
- {qbraid_cli-0.8.0.dev1.dist-info → qbraid_cli-0.9.6.dist-info}/top_level.txt +0 -0
qbraid_cli/envs/app.py
CHANGED
|
@@ -1,184 +1,92 @@
|
|
|
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
|
-
import keyword
|
|
8
|
-
import re
|
|
9
9
|
import shutil
|
|
10
10
|
import subprocess
|
|
11
11
|
import sys
|
|
12
12
|
from pathlib import Path
|
|
13
|
-
from typing import
|
|
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
|
-
from qbraid_cli.
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
def is_valid_env_name(env_name: str) -> bool: # pylint: disable=too-many-return-statements
|
|
24
|
-
"""
|
|
25
|
-
Validates a Python virtual environment name against best practices.
|
|
26
|
-
|
|
27
|
-
This function checks if the given environment name is valid based on certain
|
|
28
|
-
criteria, including length, use of special characters, reserved names, and
|
|
29
|
-
operating system-specific restrictions.
|
|
30
|
-
|
|
31
|
-
Args:
|
|
32
|
-
env_name (str): The name of the Python virtual environment to validate.
|
|
33
|
-
|
|
34
|
-
Returns:
|
|
35
|
-
bool: True if the name is valid, False otherwise.
|
|
36
|
-
|
|
37
|
-
Raises:
|
|
38
|
-
ValueError: If the environment name is not a string or is empty.
|
|
39
|
-
"""
|
|
40
|
-
# Basic checks for empty names or purely whitespace names
|
|
41
|
-
if not env_name or env_name.isspace():
|
|
42
|
-
return False
|
|
43
|
-
|
|
44
|
-
# Check for invalid characters, including shell metacharacters and spaces
|
|
45
|
-
if re.search(r'[<>:"/\\|?*\s&;()$[\]#~!{}]', env_name):
|
|
46
|
-
return False
|
|
47
|
-
|
|
48
|
-
if env_name.startswith("tmp"):
|
|
49
|
-
return False
|
|
50
|
-
|
|
51
|
-
# Reserved names for Windows (example list, can be expanded)
|
|
52
|
-
reserved_names = [
|
|
53
|
-
"CON",
|
|
54
|
-
"PRN",
|
|
55
|
-
"AUX",
|
|
56
|
-
"NUL",
|
|
57
|
-
"COM1",
|
|
58
|
-
"COM2",
|
|
59
|
-
"COM3",
|
|
60
|
-
"COM4",
|
|
61
|
-
"COM5",
|
|
62
|
-
"COM6",
|
|
63
|
-
"COM7",
|
|
64
|
-
"COM8",
|
|
65
|
-
"COM9",
|
|
66
|
-
"LPT1",
|
|
67
|
-
"LPT2",
|
|
68
|
-
"LPT3",
|
|
69
|
-
"LPT4",
|
|
70
|
-
"LPT5",
|
|
71
|
-
"LPT6",
|
|
72
|
-
"LPT7",
|
|
73
|
-
"LPT8",
|
|
74
|
-
"LPT9",
|
|
75
|
-
]
|
|
76
|
-
if env_name.upper() in reserved_names:
|
|
77
|
-
return False
|
|
78
|
-
|
|
79
|
-
if len(env_name) > 20:
|
|
80
|
-
return False
|
|
81
|
-
|
|
82
|
-
# Check against Python reserved words
|
|
83
|
-
if keyword.iskeyword(env_name):
|
|
84
|
-
return False
|
|
85
|
-
|
|
86
|
-
# Check if it starts with a number, which is not a good practice
|
|
87
|
-
if env_name[0].isdigit():
|
|
88
|
-
return False
|
|
89
|
-
|
|
90
|
-
return True
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
def validate_env_name(value: str) -> str:
|
|
94
|
-
"""Validate environment name."""
|
|
95
|
-
if not is_valid_env_name(value):
|
|
96
|
-
raise typer.BadParameter(
|
|
97
|
-
f"Invalid environment name '{value}'. " "Please use a valid Python environment name."
|
|
98
|
-
)
|
|
99
|
-
return value
|
|
100
|
-
|
|
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
|
|
101
23
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
from qbraid.api.system import get_qbraid_envs_paths, is_valid_slug
|
|
24
|
+
if TYPE_CHECKING:
|
|
25
|
+
from qbraid_core.services.environments.client import EnvironmentManagerClient as EMC
|
|
105
26
|
|
|
106
|
-
|
|
107
|
-
aliases = {}
|
|
27
|
+
envs_app = typer.Typer(help="Manage qBraid environments.", no_args_is_help=True)
|
|
108
28
|
|
|
109
|
-
qbraid_env_paths: List[Path] = get_qbraid_envs_paths()
|
|
110
29
|
|
|
111
|
-
|
|
112
|
-
for entry in env_path.iterdir():
|
|
113
|
-
if entry.is_dir() and is_valid_slug(entry.name):
|
|
114
|
-
installed[entry.name] = entry
|
|
115
|
-
|
|
116
|
-
if entry.name == "qbraid_000000":
|
|
117
|
-
aliases["default"] = entry.name
|
|
118
|
-
continue
|
|
119
|
-
|
|
120
|
-
state_json_path = entry / "state.json"
|
|
121
|
-
if state_json_path.exists():
|
|
122
|
-
try:
|
|
123
|
-
with open(state_json_path, "r", encoding="utf-8") as f:
|
|
124
|
-
data = json.load(f)
|
|
125
|
-
aliases[data.get("name", entry.name[:-7])] = entry.name
|
|
126
|
-
# pylint: disable-next=broad-exception-caught
|
|
127
|
-
except (json.JSONDecodeError, Exception):
|
|
128
|
-
aliases[entry.name[:-7]] = entry.name
|
|
129
|
-
else:
|
|
130
|
-
aliases[entry.name[:-7]] = entry.name
|
|
131
|
-
|
|
132
|
-
return installed, aliases
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
def request_delete_env(slug: str) -> str:
|
|
136
|
-
"""Send request to delete environment given slug."""
|
|
137
|
-
from qbraid.api import QbraidSession, RequestsApiError
|
|
138
|
-
|
|
139
|
-
session = QbraidSession()
|
|
140
|
-
|
|
141
|
-
try:
|
|
142
|
-
session.delete(f"/environments/{slug}")
|
|
143
|
-
except RequestsApiError as err:
|
|
144
|
-
raise QbraidException("Delete environment request failed") from err
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
@app.command(name="create")
|
|
30
|
+
@envs_app.command(name="create")
|
|
148
31
|
def envs_create( # pylint: disable=too-many-statements
|
|
149
|
-
name: str = typer.Option(
|
|
150
|
-
..., "--name", "-n", help="Name of the environment to create", callback=validate_env_name
|
|
151
|
-
),
|
|
32
|
+
name: str = typer.Option(None, "--name", "-n", help="Name of the environment to create"),
|
|
152
33
|
description: Optional[str] = typer.Option(
|
|
153
34
|
None, "--description", "-d", help="Short description of the environment"
|
|
154
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
|
+
),
|
|
155
42
|
) -> None:
|
|
156
43
|
"""Create a new qBraid environment."""
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
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
|
+
)
|
|
164
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:
|
|
165
69
|
try:
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
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))
|
|
169
74
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
75
|
+
if not name:
|
|
76
|
+
name = custom_env_data.name
|
|
77
|
+
|
|
78
|
+
def create_environment(*args, **kwargs) -> "tuple[dict, EMC]":
|
|
79
|
+
"""Create a qBraid environment."""
|
|
80
|
+
from qbraid_core.services.environments.client import EnvironmentManagerClient
|
|
174
81
|
|
|
175
|
-
|
|
82
|
+
client = EnvironmentManagerClient()
|
|
83
|
+
return client.create_environment(*args, **kwargs), client
|
|
176
84
|
|
|
177
|
-
def gather_local_data() ->
|
|
85
|
+
def gather_local_data() -> tuple[Path, str]:
|
|
178
86
|
"""Gather environment data and return the slug."""
|
|
179
|
-
from
|
|
87
|
+
from qbraid_core.services.environments import get_default_envs_paths
|
|
180
88
|
|
|
181
|
-
env_path =
|
|
89
|
+
env_path = get_default_envs_paths()[0]
|
|
182
90
|
|
|
183
91
|
result = subprocess.run(
|
|
184
92
|
[sys.executable, "--version"],
|
|
@@ -191,20 +99,15 @@ def envs_create( # pylint: disable=too-many-statements
|
|
|
191
99
|
|
|
192
100
|
return env_path, python_version
|
|
193
101
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
environment = run_progress_task(
|
|
206
|
-
request_new_env,
|
|
207
|
-
req_body,
|
|
102
|
+
if not custom_env_data:
|
|
103
|
+
custom_env_data = EnvironmentConfig(
|
|
104
|
+
name=name,
|
|
105
|
+
description=env_description,
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
environment, emc = run_progress_task(
|
|
109
|
+
create_environment,
|
|
110
|
+
custom_env_data,
|
|
208
111
|
description="Validating request...",
|
|
209
112
|
error_message="Failed to create qBraid environment",
|
|
210
113
|
)
|
|
@@ -225,7 +128,7 @@ def envs_create( # pylint: disable=too-many-statements
|
|
|
225
128
|
slug_path = env_path / slug
|
|
226
129
|
description = "None" if description == "" else description
|
|
227
130
|
|
|
228
|
-
typer.echo("
|
|
131
|
+
typer.echo("## qBraid Metadata ##\n")
|
|
229
132
|
typer.echo(f" name: {display_name}")
|
|
230
133
|
typer.echo(f" description: {description}")
|
|
231
134
|
typer.echo(f" tags: {tags}")
|
|
@@ -237,10 +140,10 @@ def envs_create( # pylint: disable=too-many-statements
|
|
|
237
140
|
typer.echo(f" location: {slug_path}")
|
|
238
141
|
typer.echo(f" version: {python_version}\n")
|
|
239
142
|
|
|
240
|
-
user_confirmation = typer.confirm("Proceed", default=True)
|
|
143
|
+
user_confirmation = auto_confirm or typer.confirm("Proceed", default=True)
|
|
241
144
|
typer.echo("")
|
|
242
145
|
if not user_confirmation:
|
|
243
|
-
|
|
146
|
+
emc.delete_environment(slug)
|
|
244
147
|
typer.echo("qBraidSystemExit: Exiting.")
|
|
245
148
|
raise typer.Exit()
|
|
246
149
|
|
|
@@ -264,7 +167,7 @@ def envs_create( # pylint: disable=too-many-statements
|
|
|
264
167
|
|
|
265
168
|
console = Console()
|
|
266
169
|
console.print(
|
|
267
|
-
f"
|
|
170
|
+
f"[bold green]Successfully created qBraid environment: "
|
|
268
171
|
f"[/bold green][bold magenta]{name}[/bold magenta]\n"
|
|
269
172
|
)
|
|
270
173
|
typer.echo("# To activate this environment, use")
|
|
@@ -276,13 +179,23 @@ def envs_create( # pylint: disable=too-many-statements
|
|
|
276
179
|
typer.echo("# $ deactivate")
|
|
277
180
|
|
|
278
181
|
|
|
279
|
-
@
|
|
182
|
+
@envs_app.command(name="remove")
|
|
280
183
|
def envs_remove(
|
|
281
|
-
name: str = typer.Option(..., "-n", "--name", help="Name of the environment to 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
|
+
),
|
|
282
188
|
) -> None:
|
|
283
189
|
"""Delete a qBraid environment."""
|
|
284
190
|
|
|
285
|
-
def
|
|
191
|
+
def delete_environment(slug: str) -> None:
|
|
192
|
+
"""Delete a qBraid environment."""
|
|
193
|
+
from qbraid_core.services.environments.client import EnvironmentManagerClient
|
|
194
|
+
|
|
195
|
+
emc = EnvironmentManagerClient()
|
|
196
|
+
emc.delete_environment(slug)
|
|
197
|
+
|
|
198
|
+
def gather_local_data(env_name: str) -> tuple[Path, str]:
|
|
286
199
|
"""Get environment path and slug from name (alias)."""
|
|
287
200
|
installed, aliases = installed_envs_data()
|
|
288
201
|
for alias, slug in aliases.items():
|
|
@@ -304,11 +217,10 @@ def envs_remove(
|
|
|
304
217
|
"Are you sure you want to continue?"
|
|
305
218
|
)
|
|
306
219
|
|
|
307
|
-
|
|
308
|
-
if typer.confirm(confirmation_message, abort=True):
|
|
220
|
+
if auto_confirm or typer.confirm(confirmation_message, abort=True):
|
|
309
221
|
typer.echo("")
|
|
310
222
|
run_progress_task(
|
|
311
|
-
|
|
223
|
+
delete_environment,
|
|
312
224
|
slug,
|
|
313
225
|
description="Deleting remote environment data...",
|
|
314
226
|
error_message="Failed to delete qBraid environment",
|
|
@@ -320,26 +232,25 @@ def envs_remove(
|
|
|
320
232
|
description="Deleting local environment...",
|
|
321
233
|
error_message="Failed to delete qBraid environment",
|
|
322
234
|
)
|
|
323
|
-
typer.echo(f"
|
|
324
|
-
# console = Console()
|
|
325
|
-
# console.print(
|
|
326
|
-
# f"\n[bold green]Successfully deleted qBraid environment: "
|
|
327
|
-
# f"[/bold green][bold magenta]{name}[/bold magenta]\n"
|
|
328
|
-
# )
|
|
235
|
+
typer.echo(f"Environment '{name}' successfully removed.")
|
|
329
236
|
|
|
330
237
|
|
|
331
|
-
@
|
|
238
|
+
@envs_app.command(name="list")
|
|
332
239
|
def envs_list():
|
|
333
240
|
"""List installed qBraid environments."""
|
|
334
241
|
installed, aliases = installed_envs_data()
|
|
335
242
|
|
|
243
|
+
console = Console()
|
|
244
|
+
|
|
336
245
|
if len(installed) == 0:
|
|
337
|
-
print(
|
|
338
|
-
|
|
246
|
+
console.print(
|
|
247
|
+
"No qBraid environments installed.\n\n"
|
|
248
|
+
+ "Use 'qbraid envs create' to create a new environment.",
|
|
249
|
+
style="yellow",
|
|
250
|
+
)
|
|
339
251
|
return
|
|
340
252
|
|
|
341
253
|
alias_path_pairs = [(alias, installed[slug_name]) for alias, slug_name in aliases.items()]
|
|
342
|
-
|
|
343
254
|
sorted_alias_path_pairs = sorted(
|
|
344
255
|
alias_path_pairs,
|
|
345
256
|
key=lambda x: (x[0] != "default", str(x[1]).startswith(str(Path.home())), x[0]),
|
|
@@ -348,23 +259,31 @@ def envs_list():
|
|
|
348
259
|
current_env_path = Path(sys.executable).parent.parent.parent
|
|
349
260
|
|
|
350
261
|
max_alias_length = (
|
|
351
|
-
max(len(alias) for alias,
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
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
|
|
355
265
|
)
|
|
356
266
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
267
|
+
output_lines = []
|
|
268
|
+
output_lines.append("# qbraid environments:")
|
|
269
|
+
output_lines.append("#")
|
|
270
|
+
output_lines.append("")
|
|
271
|
+
|
|
360
272
|
for alias, path in sorted_alias_path_pairs:
|
|
361
|
-
mark = "*
|
|
362
|
-
|
|
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)
|
|
363
278
|
|
|
279
|
+
console.print(final_output)
|
|
364
280
|
|
|
365
|
-
|
|
281
|
+
|
|
282
|
+
@envs_app.command(name="activate")
|
|
366
283
|
def envs_activate(
|
|
367
|
-
name: str = typer.Argument(
|
|
284
|
+
name: str = typer.Argument(
|
|
285
|
+
..., help="Name of the environment. Values from 'qbraid envs list'."
|
|
286
|
+
),
|
|
368
287
|
):
|
|
369
288
|
"""Activate qBraid environment.
|
|
370
289
|
|
|
@@ -384,4 +303,4 @@ def envs_activate(
|
|
|
384
303
|
|
|
385
304
|
|
|
386
305
|
if __name__ == "__main__":
|
|
387
|
-
|
|
306
|
+
envs_app()
|
qbraid_cli/envs/create.py
CHANGED
|
@@ -1,125 +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 replace_str(target: str, replacement: str, file_path: str) -> None:
|
|
15
|
-
"""Replace all instances of string in file"""
|
|
16
|
-
with open(file_path, "r", encoding="utf-8") as file:
|
|
17
|
-
content = file.read()
|
|
18
|
-
|
|
19
|
-
content = content.replace(target, replacement)
|
|
20
|
-
|
|
21
|
-
with open(file_path, "w", encoding="utf-8") as file:
|
|
22
|
-
file.write(content)
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
def update_state_json(
|
|
26
|
-
slug_path: str,
|
|
27
|
-
install_complete: int,
|
|
28
|
-
install_success: int,
|
|
29
|
-
message: Optional[str] = None,
|
|
30
|
-
env_name: Optional[str] = None,
|
|
31
|
-
) -> None:
|
|
32
|
-
"""Update environment's install status values in a JSON file.
|
|
33
|
-
Truth table values: 0 = False, 1 = True, -1 = Unknown
|
|
34
|
-
"""
|
|
35
|
-
# Set default message if none provided
|
|
36
|
-
message = "" if message is None else message.replace("\n", " ")
|
|
37
|
-
|
|
38
|
-
# File path for state.json
|
|
39
|
-
state_json_path = os.path.join(slug_path, "state.json")
|
|
40
|
-
|
|
41
|
-
# Read existing data or use default structure
|
|
42
|
-
if os.path.exists(state_json_path):
|
|
43
|
-
with open(state_json_path, "r", encoding="utf-8") as f:
|
|
44
|
-
data = json.load(f)
|
|
45
|
-
else:
|
|
46
|
-
data = {"install": {}}
|
|
47
9
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
data["install"]["message"] = message
|
|
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["name"] = env_name
|
|
14
|
+
return create_local_venv(*args, **kwargs)
|
|
55
15
|
|
|
56
|
-
# Write updated data back to state.json
|
|
57
|
-
with open(state_json_path, "w", encoding="utf-8") as f:
|
|
58
|
-
json.dump(data, f, indent=4)
|
|
59
16
|
|
|
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
|
|
60
20
|
|
|
61
|
-
|
|
62
|
-
"""Create virtual environment and swap PS1 display name."""
|
|
63
|
-
venv_path = os.path.join(slug_path, "pyenv")
|
|
64
|
-
subprocess.run([sys.executable, "-m", "venv", venv_path], check=True)
|
|
65
|
-
|
|
66
|
-
# Determine the correct directory for activation scripts based on the operating system
|
|
67
|
-
if sys.platform == "win32":
|
|
68
|
-
scripts_path = os.path.join(venv_path, "Scripts")
|
|
69
|
-
activate_files = ["activate.bat", "Activate.ps1"]
|
|
70
|
-
else:
|
|
71
|
-
scripts_path = os.path.join(venv_path, "bin")
|
|
72
|
-
activate_files = ["activate", "activate.csh", "activate.fish"]
|
|
73
|
-
|
|
74
|
-
for file in activate_files:
|
|
75
|
-
file_path = os.path.join(scripts_path, file)
|
|
76
|
-
if os.path.isfile(file_path):
|
|
77
|
-
replace_str("(pyenv)", f"({prompt})", file_path)
|
|
78
|
-
|
|
79
|
-
replace_str(
|
|
80
|
-
"include-system-site-packages = false",
|
|
81
|
-
"include-system-site-packages = true",
|
|
82
|
-
os.path.join(venv_path, "pyvenv.cfg"),
|
|
83
|
-
)
|
|
84
|
-
|
|
85
|
-
update_state_json(slug_path, 1, 1)
|
|
21
|
+
return update_state(*ags, **kwargs)
|
|
86
22
|
|
|
87
23
|
|
|
88
24
|
def create_qbraid_env_assets(slug: str, alias: str, kernel_name: str, slug_path: str) -> None:
|
|
89
25
|
"""Create a qBraid environment including python venv, PS1 configs,
|
|
90
26
|
kernel resource files, and qBraid state.json."""
|
|
91
|
-
|
|
92
|
-
from jupyter_client.kernelspec import KernelSpecManager
|
|
93
|
-
|
|
94
|
-
local_resource_dir = os.path.join(slug_path, "kernels", f"python3_{slug}")
|
|
95
|
-
os.makedirs(local_resource_dir, exist_ok=True)
|
|
96
|
-
|
|
97
|
-
# create state.json
|
|
98
|
-
update_state_json(slug_path, 0, 0, env_name=alias)
|
|
99
|
-
|
|
100
|
-
# create kernel.json
|
|
101
|
-
kernel_json_path = os.path.join(local_resource_dir, "kernel.json")
|
|
102
|
-
kernel_spec_manager = KernelSpecManager()
|
|
103
|
-
kernelspec_dict = kernel_spec_manager.get_all_specs()
|
|
104
|
-
kernel_data = kernelspec_dict["python3"]["spec"]
|
|
105
|
-
if sys.platform == "win32":
|
|
106
|
-
python_exec_path = os.path.join(slug_path, "pyenv", "Scripts", "python.exe")
|
|
107
|
-
else:
|
|
108
|
-
python_exec_path = os.path.join(slug_path, "pyenv", "bin", "python")
|
|
109
|
-
kernel_data["argv"][0] = python_exec_path
|
|
110
|
-
kernel_data["display_name"] = kernel_name
|
|
111
|
-
with open(kernel_json_path, "w", encoding="utf-8") as file:
|
|
112
|
-
json.dump(kernel_data, file, indent=4)
|
|
113
|
-
|
|
114
|
-
# copy logo files
|
|
115
|
-
sys_resource_dir = kernelspec_dict["python3"]["resource_dir"]
|
|
116
|
-
logo_files = ["logo-32x32.png", "logo-64x64.png", "logo-svg.svg"]
|
|
117
|
-
|
|
118
|
-
for file in logo_files:
|
|
119
|
-
sys_path = os.path.join(sys_resource_dir, file)
|
|
120
|
-
loc_path = os.path.join(local_resource_dir, file)
|
|
121
|
-
if os.path.isfile(sys_path):
|
|
122
|
-
shutil.copy(sys_path, loc_path)
|
|
27
|
+
from qbraid_core.services.environments.create import create_qbraid_env_assets as create_assets
|
|
123
28
|
|
|
124
|
-
|
|
125
|
-
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