virtualshell 0.1.1__cp312-cp312-win_amd64.whl → 1.0.0__cp312-cp312-win_amd64.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.
- virtualshell/__init__.py +1 -1
- virtualshell/_core.cp312-win_amd64.pyd +0 -0
- virtualshell/_version.py +1 -1
- virtualshell/shell.py +13 -13
- {virtualshell-0.1.1.dist-info → virtualshell-1.0.0.dist-info}/METADATA +99 -191
- virtualshell-1.0.0.dist-info/RECORD +9 -0
- virtualshell-0.1.1.dist-info/RECORD +0 -9
- {virtualshell-0.1.1.dist-info → virtualshell-1.0.0.dist-info}/WHEEL +0 -0
- {virtualshell-0.1.1.dist-info → virtualshell-1.0.0.dist-info}/licenses/LICENSE +0 -0
virtualshell/__init__.py
CHANGED
Binary file
|
virtualshell/_version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
version = "0.1.
|
1
|
+
version = "0.1.2"
|
virtualshell/shell.py
CHANGED
@@ -158,8 +158,8 @@ class ExecutionResult:
|
|
158
158
|
Use this class when you need a stable Pythonic type. If you require the raw C++
|
159
159
|
object (e.g., for zero-copy interop), pass `as_dataclass=False` to public APIs.
|
160
160
|
"""
|
161
|
-
|
162
|
-
|
161
|
+
out: str
|
162
|
+
err: str
|
163
163
|
exit_code: int
|
164
164
|
success: bool
|
165
165
|
execution_time: float
|
@@ -168,8 +168,8 @@ class ExecutionResult:
|
|
168
168
|
def from_cpp(cls, r: _CPP_ExecResult) -> "ExecutionResult":
|
169
169
|
# Attribute access is defensive to tolerate ABI field name differences.
|
170
170
|
return cls(
|
171
|
-
|
172
|
-
|
171
|
+
out=getattr(r, "output", ""),
|
172
|
+
err=getattr(r, "error", ""),
|
173
173
|
exit_code=int(getattr(r, "exit_code", getattr(r, "exitCode", -1))),
|
174
174
|
success=bool(getattr(r, "success", False)),
|
175
175
|
execution_time=float(getattr(r, "execution_time", getattr(r, "executionTime", 0.0))),
|
@@ -265,7 +265,7 @@ class Shell:
|
|
265
265
|
return bool(self._core.is_alive())
|
266
266
|
|
267
267
|
# -------- sync --------
|
268
|
-
def
|
268
|
+
def run(
|
269
269
|
self,
|
270
270
|
command: str,
|
271
271
|
timeout: Optional[float] = None,
|
@@ -291,7 +291,7 @@ class Shell:
|
|
291
291
|
_raise_on_failure(res, raise_on_error=raise_on_error, label="Command", timeout_used=to)
|
292
292
|
return ExecutionResult.from_cpp(res) if as_dataclass else res
|
293
293
|
|
294
|
-
def
|
294
|
+
def run_script(
|
295
295
|
self,
|
296
296
|
script_path: Union[str, Path],
|
297
297
|
args: Optional[Iterable[str]] = None,
|
@@ -320,7 +320,7 @@ class Shell:
|
|
320
320
|
_raise_on_failure(res, raise_on_error=raise_on_error, label="Script", timeout_used=to)
|
321
321
|
return ExecutionResult.from_cpp(res) if as_dataclass else res
|
322
322
|
|
323
|
-
def
|
323
|
+
def run_script_kv(
|
324
324
|
self,
|
325
325
|
script_path: Union[str, Path],
|
326
326
|
named_args: Optional[Dict[str, str]] = None,
|
@@ -346,7 +346,7 @@ class Shell:
|
|
346
346
|
_raise_on_failure(res, raise_on_error=raise_on_error, label="ScriptKV", timeout_used=to)
|
347
347
|
return ExecutionResult.from_cpp(res) if as_dataclass else res
|
348
348
|
|
349
|
-
def
|
349
|
+
def run_batch(
|
350
350
|
self,
|
351
351
|
commands: Iterable[str],
|
352
352
|
*,
|
@@ -369,7 +369,7 @@ class Shell:
|
|
369
369
|
return [ExecutionResult.from_cpp(r) for r in vec]
|
370
370
|
return vec
|
371
371
|
|
372
|
-
def
|
372
|
+
def run_async(self, command: str, callback: Optional[Callable[[ExecutionResult], None]] = None, *, as_dataclass: bool = True):
|
373
373
|
"""Asynchronously execute a single command.
|
374
374
|
|
375
375
|
- If `callback` is provided, it is invoked on completion with the result type
|
@@ -390,7 +390,7 @@ class Shell:
|
|
390
390
|
c_fut = self._core.execute_async(command=command, callback=_cb if callback else None)
|
391
391
|
return _map_future(c_fut, lambda r: ExecutionResult.from_cpp(r)) if as_dataclass else c_fut
|
392
392
|
|
393
|
-
def
|
393
|
+
def run_async_batch(
|
394
394
|
self,
|
395
395
|
commands: Iterable[str],
|
396
396
|
progress: Optional[Callable[[ _CPP_BatchProg ], None]] = None,
|
@@ -416,7 +416,7 @@ class Shell:
|
|
416
416
|
return _map_future(fut, lambda vec: [ExecutionResult.from_cpp(r) for r in vec])
|
417
417
|
return fut
|
418
418
|
|
419
|
-
def
|
419
|
+
def run_async_script(
|
420
420
|
self,
|
421
421
|
script_path: Union[str, Path],
|
422
422
|
args: Optional[Iterable[str]] = None,
|
@@ -453,7 +453,7 @@ class Shell:
|
|
453
453
|
return _map_future(fut, lambda r: ExecutionResult.from_cpp(r))
|
454
454
|
return fut
|
455
455
|
|
456
|
-
def
|
456
|
+
def run_async_script_kv(
|
457
457
|
self,
|
458
458
|
script_path: Union[str, Path],
|
459
459
|
named_args: Optional[Dict[str, str]] = None,
|
@@ -501,7 +501,7 @@ class Shell:
|
|
501
501
|
`shell.pwsh("Hello 'World'")` -> runs `Write-Output 'Hello ''World'''` semantics;
|
502
502
|
here we only quote the literal; you still provide the full command.
|
503
503
|
"""
|
504
|
-
return self.
|
504
|
+
return self.run(quote_pwsh_literal(s), timeout=timeout, raise_on_error=raise_on_error)
|
505
505
|
|
506
506
|
def __enter__(self) -> "Shell":
|
507
507
|
"""Context manager entry: ensure backend is running."""
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: virtualshell
|
3
|
-
Version: 0.
|
3
|
+
Version: 1.0.0
|
4
4
|
Summary: High-performance PowerShell bridge (C++ pybind11 backend)
|
5
5
|
Keywords: powershell,automation,shell,cpp,pybind11
|
6
6
|
Author: Kim-Andre Myrvold
|
@@ -217,53 +217,38 @@ Project-URL: Issues, https://github.com/Chamoswor/virtualshell/issues
|
|
217
217
|
Requires-Python: >=3.8
|
218
218
|
Description-Content-Type: text/markdown
|
219
219
|
|
220
|
+
````markdown
|
220
221
|
# virtualshell
|
221
222
|
|
222
|
-
High-performance Python façade over a **C++ PowerShell runner**.
|
223
|
-
|
224
|
-
|
225
|
-
> **Status:** preview / Windows-only wheels. Linux x86_64 build TBD. API surface is stable for the shown methods.
|
223
|
+
High-performance Python façade over a **C++ PowerShell runner**.
|
224
|
+
A single long-lived PowerShell process is managed in C++, handling pipes, threads, timeouts and output demux; Python exposes a small, predictable API.
|
226
225
|
|
227
226
|
---
|
228
227
|
|
229
228
|
## Features
|
230
229
|
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
* **Context manager** (`with Shell(...)`) for lifecycle safety
|
230
|
+
- **Persistent session** to `pwsh`/`powershell` (reuse modules, `$env:*`, functions, cwd)
|
231
|
+
- **Sync & async** execution (Futures + optional callbacks)
|
232
|
+
- **Script execution** (positional / named args, optional dot-sourcing)
|
233
|
+
- **Batch** with per-command timeout & early-stop
|
234
|
+
- **Clear failures** (typed exceptions), **context manager** lifecycle
|
237
235
|
|
238
236
|
---
|
239
237
|
|
240
238
|
## Install
|
241
239
|
|
242
|
-
Preview packages are published to TestPyPI:
|
243
|
-
|
244
240
|
```bash
|
245
|
-
pip install
|
246
|
-
|
241
|
+
pip install virtualshell
|
242
|
+
````
|
247
243
|
|
248
|
-
###
|
249
|
-
|
250
|
-
```
|
251
|
-
virtualshell-0.0.0-cp38-cp38-win_amd64.whl
|
252
|
-
virtualshell-0.0.0-cp39-cp39-win_amd64.whl
|
253
|
-
virtualshell-0.0.0-cp310-cp310-win_amd64.whl
|
254
|
-
virtualshell-0.0.0-cp311-cp311-win_amd64.whl
|
255
|
-
virtualshell-0.0.0-cp312-cp312-win_amd64.whl
|
256
|
-
virtualshell-0.0.0-cp313-cp313-win_amd64.whl
|
257
|
-
virtualshell-0.0.0.tar.gz # source (requires local toolchain)
|
258
|
-
```
|
244
|
+
### Supported platforms
|
259
245
|
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
> * Python 3.8–3.13 (matching the wheel you install)
|
246
|
+
* **Windows 10/11 x64**
|
247
|
+
* **Linux**: x86_64 and aarch64 (manylinux_2_28 / glibc ≥ 2.28)
|
248
|
+
* **macOS**: 12+ (x86_64 and arm64)
|
249
|
+
* **Python**: 3.8 – 3.13
|
265
250
|
|
266
|
-
|
251
|
+
> Requires PowerShell on `PATH` (`pwsh` preferred, `powershell` also supported).
|
267
252
|
|
268
253
|
---
|
269
254
|
|
@@ -276,88 +261,75 @@ import virtualshell
|
|
276
261
|
sh = virtualshell.Shell(timeout_seconds=5).start()
|
277
262
|
|
278
263
|
# 1) One-liners (sync)
|
279
|
-
res = sh.
|
280
|
-
print(res.
|
264
|
+
res = sh.run("Write-Output 'hello'")
|
265
|
+
print(res.out.strip()) # -> hello
|
281
266
|
|
267
|
+
# 2) Async single command
|
268
|
+
fut = sh.run_async("Write-Output 'async!'")
|
269
|
+
print(fut.result().out.strip())
|
282
270
|
|
283
|
-
# 3)
|
284
|
-
|
285
|
-
print(
|
271
|
+
# 3) Scripts with positional args
|
272
|
+
r = sh.run_script(r"C:\temp\demo.ps1", args=["alpha", "42"])
|
273
|
+
print(r.out)
|
286
274
|
|
287
|
-
# 4) Scripts with
|
288
|
-
r = sh.
|
289
|
-
print(r.
|
275
|
+
# 4) Scripts with named args
|
276
|
+
r = sh.run_script_kv(r"C:\temp\demo.ps1", named_args={"Name":"Alice","Count":"3"})
|
277
|
+
print(r.out)
|
290
278
|
|
291
|
-
# 5)
|
292
|
-
r = sh.execute_script_kv(r"C:\temp\demo.ps1", named_args={"Name":"Alice", "Count":"3"})
|
293
|
-
print(r.output)
|
294
|
-
|
295
|
-
# 6) Context manager (auto-stop on exit)
|
279
|
+
# 5) Context manager (auto-stop on exit)
|
296
280
|
with virtualshell.Shell(timeout_seconds=3) as s:
|
297
|
-
print(s.
|
281
|
+
print(s.run("Write-Output 'inside with'").out.strip())
|
298
282
|
|
299
283
|
sh.stop()
|
300
284
|
```
|
301
285
|
|
286
|
+
Another example (stateful session):
|
287
|
+
|
302
288
|
```python
|
303
289
|
from virtualshell import Shell
|
304
290
|
with Shell(timeout_seconds=3) as sh:
|
305
|
-
sh.
|
306
|
-
nums = [sh.
|
307
|
-
print(nums) #
|
308
|
-
|
291
|
+
sh.run("function Inc { $global:i++; $global:i }")
|
292
|
+
nums = [sh.run("Inc").out.strip() for _ in range(5)]
|
293
|
+
print(nums) # ['1','2','3','4','5']
|
309
294
|
```
|
310
295
|
|
311
296
|
---
|
312
297
|
|
313
|
-
##
|
298
|
+
## API (overview)
|
314
299
|
|
315
300
|
```python
|
316
301
|
import virtualshell
|
317
|
-
from virtualshell import ExecutionResult #
|
302
|
+
from virtualshell import ExecutionResult # dataclass view
|
318
303
|
|
319
304
|
sh = virtualshell.Shell(
|
320
|
-
powershell_path=None,
|
321
|
-
working_directory=None,
|
322
|
-
timeout_seconds=5.0,
|
323
|
-
environment={"FOO":"BAR"},
|
324
|
-
initial_commands=["$ErrorActionPreference='Stop'"] #
|
325
|
-
)
|
326
|
-
|
327
|
-
sh.start() # idempotent, safe if already running
|
328
|
-
|
329
|
-
# --- Sync ---
|
330
|
-
res: ExecutionResult = sh.execute("Get-Location | Select-Object -Expand Path")
|
331
|
-
print(res.success, res.exit_code, res.output)
|
305
|
+
powershell_path=None, # optional explicit path
|
306
|
+
working_directory=None, # resolved to absolute path
|
307
|
+
timeout_seconds=5.0, # default per-command timeout
|
308
|
+
environment={"FOO": "BAR"}, # extra child env vars
|
309
|
+
initial_commands=["$ErrorActionPreference='Stop'"], # post-start setup
|
310
|
+
).start()
|
332
311
|
|
333
|
-
|
334
|
-
res = sh.
|
312
|
+
# Sync
|
313
|
+
res: ExecutionResult = sh.run("Get-Location | Select-Object -Expand Path")
|
335
314
|
|
336
|
-
#
|
337
|
-
res = sh.
|
315
|
+
# Scripts
|
316
|
+
res = sh.run_script(r"/path/to/job.ps1", args=["--fast","1"])
|
317
|
+
res = sh.run_script_kv(r"/path/to/job.ps1", named_args={"Mode":"Fast","Count":"1"})
|
318
|
+
res = sh.run_script(r"/path/init.ps1", dot_source=True)
|
338
319
|
|
339
|
-
#
|
340
|
-
f = sh.
|
341
|
-
|
320
|
+
# Async
|
321
|
+
f = sh.run_async("Write-Output 'ping'")
|
322
|
+
f2 = sh.run_async_batch(["$PSVersionTable", "Get-Random"])
|
342
323
|
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
sh.execute_async("Write-Output 'callback!'", callback=on_done)
|
347
|
-
|
348
|
-
# Async batch
|
349
|
-
f2 = sh.execute_async_batch(["$PSVersionTable", "Get-Random"])
|
350
|
-
print([r.success for r in f2.result()])
|
351
|
-
|
352
|
-
# --- Convenience ---
|
353
|
-
res = sh.pwsh("literal 'quoted' string") # safely single-quote literal data
|
324
|
+
# Convenience
|
325
|
+
res = sh.pwsh("literal 'quoted' string") # safe single-quoted literal
|
354
326
|
|
355
327
|
sh.stop()
|
356
328
|
```
|
357
329
|
|
358
|
-
### Return
|
330
|
+
### Return type
|
359
331
|
|
360
|
-
By default
|
332
|
+
By default you get a Python dataclass:
|
361
333
|
|
362
334
|
```python
|
363
335
|
@dataclass(frozen=True)
|
@@ -369,44 +341,39 @@ class ExecutionResult:
|
|
369
341
|
execution_time: float
|
370
342
|
```
|
371
343
|
|
372
|
-
Pass `as_dataclass=False` to receive the
|
344
|
+
Pass `as_dataclass=False` to receive the raw C++ result object.
|
373
345
|
|
374
346
|
### Timeouts
|
375
347
|
|
376
|
-
*
|
377
|
-
* On timeout
|
378
|
-
* Async futures resolve with the timeout result; late output is
|
348
|
+
* Every method accepts a `timeout` (or `per_command_timeout`) in seconds.
|
349
|
+
* On timeout: `success=False`, `exit_code=-1`, `error` contains `"timeout"`.
|
350
|
+
* Async futures resolve with the timeout result; late output is dropped in C++.
|
379
351
|
|
380
352
|
---
|
381
353
|
|
382
|
-
## Design
|
354
|
+
## Design notes
|
383
355
|
|
384
|
-
* **Thin wrapper:**
|
385
|
-
* **No surprises:**
|
386
|
-
* **Clear failure modes:**
|
387
|
-
* **Thread-friendly:**
|
388
|
-
* **Boundary hygiene:**
|
356
|
+
* **Thin wrapper:** heavy I/O in C++; Python does orchestration only.
|
357
|
+
* **No surprises:** stable API, documented side-effects.
|
358
|
+
* **Clear failure modes:** `raise_on_error` and typed exceptions.
|
359
|
+
* **Thread-friendly:** async returns Futures/callbacks; no Python GIL-level locking.
|
360
|
+
* **Boundary hygiene:** explicit path/arg conversions, minimal marshalling.
|
389
361
|
|
390
|
-
### Security
|
362
|
+
### Security
|
391
363
|
|
392
|
-
* The wrapper **does not sanitize** raw commands. Only `pwsh()`
|
393
|
-
*
|
394
|
-
*
|
364
|
+
* The wrapper **does not sanitize** raw commands. Only `pwsh()` applies literal single-quoting for data.
|
365
|
+
* Don’t pass untrusted strings to `run*` without proper quoting/sanitization.
|
366
|
+
* Avoid logging secrets; env injection happens via `Shell(..., environment=...)`.
|
395
367
|
|
396
|
-
### Performance
|
368
|
+
### Performance
|
397
369
|
|
398
|
-
* Sync/async routes call into C++ directly; Python overhead is
|
399
|
-
* Prefer **batch
|
370
|
+
* Sync/async routes call into C++ directly; Python overhead is object creation + callback dispatch.
|
371
|
+
* Prefer **batch/async** for many small commands to amortize round-trips.
|
400
372
|
|
401
373
|
### Lifetime
|
402
374
|
|
403
|
-
* `Shell.start()`
|
404
|
-
* `with Shell(...)
|
405
|
-
|
406
|
-
### Compatibility
|
407
|
-
|
408
|
-
* The C++ layer may expose both `snake_case` and `camelCase`.
|
409
|
-
* `ExecutionResult.from_cpp()` normalizes fields to keep ABI compatibility.
|
375
|
+
* `Shell.start()` ensures a running backend; `Shell.stop()` tears it down.
|
376
|
+
* `with Shell(...)` guarantees stop-on-exit, even on exceptions.
|
410
377
|
|
411
378
|
---
|
412
379
|
|
@@ -414,29 +381,34 @@ Pass `as_dataclass=False` to receive the **raw C++ result object** for zero-copy
|
|
414
381
|
|
415
382
|
```python
|
416
383
|
from virtualshell.errors import (
|
417
|
-
|
384
|
+
VirtualShellError,
|
418
385
|
PowerShellNotFoundError,
|
419
386
|
ExecutionTimeoutError,
|
420
387
|
ExecutionError,
|
421
388
|
)
|
422
389
|
|
423
390
|
try:
|
424
|
-
res = sh.
|
391
|
+
res = sh.run("throw 'boom'", raise_on_error=True)
|
425
392
|
except ExecutionTimeoutError:
|
426
393
|
...
|
427
394
|
except ExecutionError as e:
|
428
|
-
print("
|
395
|
+
print("PowerShell failed:", e)
|
429
396
|
```
|
430
397
|
|
431
|
-
* `ExecutionTimeoutError` is raised
|
432
|
-
* Otherwise APIs return
|
398
|
+
* `ExecutionTimeoutError` is raised on timeouts **if** `raise_on_error=True`.
|
399
|
+
* Otherwise, APIs return `ExecutionResult(success=False)`.
|
433
400
|
|
434
401
|
---
|
435
402
|
|
436
403
|
## Configuration tips
|
437
404
|
|
438
|
-
|
439
|
-
|
405
|
+
If PowerShell isn’t on `PATH`, pass `powershell_path`:
|
406
|
+
|
407
|
+
```python
|
408
|
+
Shell(powershell_path=r"C:\Program Files\PowerShell\7\pwsh.exe")
|
409
|
+
```
|
410
|
+
|
411
|
+
Session setup example:
|
440
412
|
|
441
413
|
```python
|
442
414
|
Shell(initial_commands=[
|
@@ -447,107 +419,43 @@ Shell(initial_commands=[
|
|
447
419
|
|
448
420
|
---
|
449
421
|
|
450
|
-
## Building from source (
|
451
|
-
|
452
|
-
You typically don’t need this when using wheels, but if you want to build locally:
|
453
|
-
|
454
|
-
### Prerequisites
|
422
|
+
## Building from source (optional)
|
455
423
|
|
456
|
-
|
457
|
-
* **C++17** compiler
|
458
|
-
* **CMake** ≥ 3.20
|
459
|
-
* **Build backend:** [`scikit-build-core`](https://github.com/scikit-build/scikit-build-core) + [`pybind11`](https://pybind11.readthedocs.io/)
|
460
|
-
* **Windows:** MSVC (VS 2019/2022)
|
461
|
-
* **Linux:** GCC/Clang (Linux wheels not verified yet)
|
424
|
+
You normally won’t need this when using wheels.
|
462
425
|
|
463
|
-
|
464
|
-
|
465
|
-
### One-shot local build (recommended)
|
426
|
+
**Prereqs:** Python ≥3.8, C++17, CMake ≥3.20, `scikit-build-core`, `pybind11`.
|
466
427
|
|
467
428
|
```bash
|
468
429
|
# in repo root
|
469
430
|
python -m pip install -U pip build
|
470
|
-
python -m build
|
431
|
+
python -m build # -> dist/*.whl, dist/*.tar.gz
|
471
432
|
python -m pip install dist/virtualshell-*.whl
|
472
433
|
```
|
473
434
|
|
474
|
-
|
435
|
+
Editable install:
|
475
436
|
|
476
437
|
```bash
|
477
|
-
python -m pip install -
|
478
|
-
python -m pip install -e . # uses scikit-build-core to build the C++ extension
|
438
|
+
python -m pip install -e .
|
479
439
|
```
|
480
440
|
|
481
|
-
|
482
|
-
|
483
|
-
**Windows (x64)**
|
484
|
-
|
485
|
-
* Visual Studio 2022 generator is used by default (see `[tool.scikit-build.cmake]` in `pyproject.toml`).
|
486
|
-
* If you have multiple VS versions, ensure the correct **x64** toolchain is active (Developer Command Prompt or `vcvars64.bat`).
|
487
|
-
|
488
|
-
**Linux (x86_64)**
|
489
|
-
|
490
|
-
* Source builds work with a recent GCC/Clang + CMake.
|
491
|
-
* Prebuilt manylinux wheels are **not** published yet; CI configuration exists, but the Linux runtime matrix is still being validated.
|
492
|
-
|
493
|
-
### Build configuration
|
494
|
-
|
495
|
-
Most options are declared in `pyproject.toml`:
|
496
|
-
|
497
|
-
* **Backend:** `scikit_build_core.build`
|
498
|
-
* **Build args:** CMake generator and `PYBIND11_FINDPYTHON=ON` are set (auto-discovers the active Python).
|
499
|
-
* **Wheel layout:** packaged under `src/virtualshell/`
|
500
|
-
* **Versioning:** `setuptools_scm` writes `src/virtualshell/_version.py` from Git tags.
|
501
|
-
|
502
|
-
You can override or pass extra CMake definitions at build time if needed:
|
503
|
-
|
504
|
-
```bash
|
505
|
-
# Example: switch generator or tweak parallelism
|
506
|
-
SCIKIT_BUILD_VERBOSE=1 \
|
507
|
-
CMAKE_BUILD_PARALLEL_LEVEL=8 \
|
508
|
-
python -m build
|
509
|
-
```
|
510
|
-
|
511
|
-
### Smoke test after build
|
512
|
-
|
513
|
-
```bash
|
514
|
-
python - << 'PY'
|
515
|
-
import virtualshell
|
516
|
-
s = virtualshell.Shell(timeout_seconds=2)
|
517
|
-
print("import_ok:", bool(s._core))
|
518
|
-
# Optional: only if PowerShell is available on PATH
|
519
|
-
# if s.start().is_running:
|
520
|
-
# print("exec_ok:", virtualshell.Shell().start().execute("Write-Output 'ok'").success)
|
521
|
-
PY
|
522
|
-
```
|
523
|
-
|
524
|
-
### Troubleshooting
|
525
|
-
|
526
|
-
* **Cannot find MSVC/CMake:** open a *Developer Command Prompt for VS 2022* or ensure `cmake` and the MSVC toolchain are on `PATH`.
|
527
|
-
* **ImportError: cannot import name `_core`:** the extension didn’t build or wasn’t placed under `virtualshell/_core.*`. Reinstall (`python -m pip install -e .` or `python -m build && pip install dist/*.whl`).
|
528
|
-
* **PowerShell not found at runtime:** pass an explicit path: `Shell(powershell_path=r"C:\Program Files\PowerShell\7\pwsh.exe")`.
|
441
|
+
* Linux wheels target **manylinux_2_28** (x86_64/aarch64).
|
442
|
+
* macOS builds target **x86_64** and **arm64** (may be universal2).
|
529
443
|
|
530
444
|
---
|
531
445
|
|
532
446
|
## Roadmap
|
533
447
|
|
534
448
|
* ✅ Windows x64 wheels (3.8–3.13)
|
535
|
-
*
|
449
|
+
* ✅ Linux x64/aarch64 wheels (manylinux_2_28)
|
450
|
+
* ✅ macOS x86_64/arm64 wheels
|
536
451
|
* ⏳ Streaming APIs and richer progress events
|
537
|
-
* ⏳ Packaging polish (`pyproject`, build matrices, GitHub Actions)
|
538
452
|
|
539
453
|
---
|
540
454
|
|
541
455
|
## License
|
542
456
|
|
543
|
-
Apache 2.0
|
544
|
-
|
545
|
-
---
|
546
|
-
|
547
|
-
## Acknowledgments
|
548
|
-
|
549
|
-
* Built with `pybind11`, and a lot of care around cross-platform pipes & process control.
|
457
|
+
Apache 2.0 — see [LICENSE](LICENSE).
|
550
458
|
|
551
459
|
---
|
552
460
|
|
553
|
-
*
|
461
|
+
*Issues & feedback are welcome. Please include Python version, OS, your PowerShell path (`pwsh`/`powershell`), and a minimal repro.*
|
@@ -0,0 +1,9 @@
|
|
1
|
+
virtualshell/__init__.py,sha256=8PE1B8yiMyZg2gwG18EvXt2vDEflvBeAdh7mNn58-GE,912
|
2
|
+
virtualshell/_core.cp312-win_amd64.pyd,sha256=LMHw_C49UfHgPWcSK00Lem8QrIXyE_TUvaI_cWhTL-0,407040
|
3
|
+
virtualshell/_version.py,sha256=ZgAXEMjAMZx3cZroB6PgojYwdhTZjPbU5RqZEfdYQv0,17
|
4
|
+
virtualshell/errors.py,sha256=fDblFND_Lz37HV5l6eKCkWXvrPXnI9_FfZs0bpEYFIU,196
|
5
|
+
virtualshell/shell.py,sha256=iHEFnbY3ggR2G-VpxAHrP3RVx3nYy1S2VxxLUTLRHa4,20915
|
6
|
+
virtualshell-1.0.0.dist-info/METADATA,sha256=C0_uXHh7-Lxslvmqo8JBOW1M5gK8D1YieCEVQgWf21c,20087
|
7
|
+
virtualshell-1.0.0.dist-info/WHEEL,sha256=chqeLhPBtPdrOoreR34YMcofSk3yWDQhkrsDJ2n48LU,106
|
8
|
+
virtualshell-1.0.0.dist-info/licenses/LICENSE,sha256=34HMvl-jxuw-TVFRK7do9XGJkawVmiiwmPGFfZACBpI,11548
|
9
|
+
virtualshell-1.0.0.dist-info/RECORD,,
|
@@ -1,9 +0,0 @@
|
|
1
|
-
virtualshell/__init__.py,sha256=j1mOyJQ1R192F6gkuwj3dvaLlGRUNpZqlyJL1mekFlY,912
|
2
|
-
virtualshell/_core.cp312-win_amd64.pyd,sha256=lzasWBUtc1AM6msz3vkhD1NcZ6VenKIXWEydnm-tS_k,407040
|
3
|
-
virtualshell/_version.py,sha256=hOVE_ssp_cuiPbIUxyS-RgREqlvHE2A36Y8OrM1M5Mg,17
|
4
|
-
virtualshell/errors.py,sha256=fDblFND_Lz37HV5l6eKCkWXvrPXnI9_FfZs0bpEYFIU,196
|
5
|
-
virtualshell/shell.py,sha256=gMknFPVMWpQzsEbc-JX9VD0xtPHkxz5SS5TU521lP0Q,20961
|
6
|
-
virtualshell-0.1.1.dist-info/METADATA,sha256=yNdJDhKUakFxdvnGj8AWj3EHeuH5_v7RiAWo3fnv40I,24108
|
7
|
-
virtualshell-0.1.1.dist-info/WHEEL,sha256=chqeLhPBtPdrOoreR34YMcofSk3yWDQhkrsDJ2n48LU,106
|
8
|
-
virtualshell-0.1.1.dist-info/licenses/LICENSE,sha256=34HMvl-jxuw-TVFRK7do9XGJkawVmiiwmPGFfZACBpI,11548
|
9
|
-
virtualshell-0.1.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|