shell-next
Persistent asynchronous Bash, PowerShell, and cmd sessions for Python 3.14+.
Bash sudo supports an upfront SessionConfig(sudo_password=...) reused by
explicitly elevated commands, or an asynchronous per-command password provider.
Follow the step-by-step tutorial for examples from basic commands through a complete workflow on all three backends. Full standalone code is in examples/.
Documentation · PyPI · Wiki drafts
from shell_next import Backend, ProcessCommand, SessionConfig, use_shell_session
async def inspect_repository(config: SessionConfig):
async with use_shell_session(config) as shell:
await shell.chdir("/srv/project")
result = await shell.run(ProcessCommand("git", ("status", "--short")), check=True)
return result.stdout_str()
Use ProcessCommand for executable arguments that must remain structural. Use
SessionScript for backend-native scripts and persistent shell variables,
functions, and aliases. Shell syntax is never translated between languages.
Install with python -m pip install shell-next. Supply
SessionConfig(backend=Backend.BASH) on Linux, or select Backend.POWERSHELL
(PowerShell 7 installed) or Backend.CMD on Windows. Python 3.14+ is required.
Interactive commands
from shell_next import CommandOptions, StdinMode
async def answer_prompt(shell, program):
options = CommandOptions(stdin=StdinMode.MANUAL)
async with shell.command(program, options=options, timeout=30) as command:
await command.expect(b"Name: ")
await command.sendline(b"Ada")
await command.close_stdin()
return await command.wait()
submit() immediately registers a command and returns its handle. One session
executes one command at a time; the default policy rejects concurrent submissions.
ConcurrencyPolicy.QUEUE enables FIFO queuing. Different sessions run independently.
Cancelling wait() cancels observation only. Cancelling run() or escaping a
command context requests termination. A force-stopped shell becomes unusable;
create another session explicitly when required.
Deterministic application tests
from shell_next import Emit, MockExpectation, MockScenario, MockShellSession
scenario = MockScenario(
[
MockExpectation(ProcessCommand("git", ("status", "--short")), (Emit(b" M README.md\n"),)),
]
)
config = SessionConfig()
config._session_cls = MockShellSession.configured(scenario)
Pass this same configuration to application code using use_shell_session.
The mock shares production lifecycle code while keeping execution, state, input,
and output in memory. Unmatched commands and unconsumed strict expectations fail.
Advance(60) advances mock time without sleeping. Plain
config._session_cls = MockShellSession creates an empty strict scenario.
Capture and capabilities
Results retain the original ProcessCommand or SessionScript as result.command.
Use result.stdout_str() and result.stderr_str() for decoded tail text (UTF-8
with replacement by default), or access raw bytes through result.stdout.tail
and result.stderr.tail.
Public records have named-field reprs with readable enum names and abbreviated large payloads. Sessions and command handles show current lifecycle state and counts. Representations preserve hidden secret fields and do not query the shell.
Set SessionConfig(capture=CaptureConfig(tail_bytes=4096)) to retain at most
4 KiB per stream; the default is 65,536 bytes (64 KiB), and zero retains no tail.
Each stream retains its own bounded tail, and
literal prompt matching uses a separate bounded window. Slow event subscribers
receive an overflow error without blocking primary capture. Opt into full capture
with CaptureConfig(directory=existing_directory). Results distinguish received
bytes, durable file bytes, truncation, sealing, and possible unread output.
Inspect shell.capabilities before requesting backend-specific behavior.
Windows active elevation and terminal/PowerShell Host prompt automation are
unsupported. The library is a process-management API, not a security sandbox
for untrusted scripts.
See the development specification, usage guide, architecture, and release checklist.
Development
python -m pip install -e ".[dev]"
python -m ruff check .
python -m mypy
python -m pytest --cov --cov-branch
python -m build
python -m twine check dist/*
The package uses only the Python standard library at runtime. Tests that start
real shells are marked integration. Test files mirror production responsibilities;
reusable test infrastructure lives in tests/support.
Metadata
Release files for shell-next 0.1.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| shell_next-0.1.3.tar.gz | 2.8 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| shell_next-0.1.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 2.8 MB
Release files / shell_next-0.1.3.tar.gz
| Download URL | shell_next-0.1.3.tar.gz |
|---|---|
| Size | 2.8 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f12a94379afb5648e03127ff1322524ce3655d957f691e004cc36ac2f95467e9
|
|
BLAKE2b-256 checksum How to use checksums |
b7b9e1cb1da873c3b83aac3e0a82ee66da57cfc203f7fcd2562222d32241b37b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.2
|
Release files / shell_next-0.1.3-py3-none-any.whl
| Download URL | shell_next-0.1.3-py3-none-any.whl |
|---|---|
| Size | 67.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5f0bc8ada6fa8c8f472070daccb5d38ea966a7b88c71f446155c02585fbd8820
|
|
BLAKE2b-256 checksum How to use checksums |
1d9053963759f530981f6a6647d1343d9ff5c1afa659a323ad0c1d0a01a73019
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.2
|