SSHreader
SSHreader is a Python library for running commands on multiple servers in parallel. It wraps Paramiko and provides both a direct SSH client and a job-based interface for parallel SSH and local shell work. It also includes pydsh, a command-line tool for running commands across host lists.
SSHreader supports Python 3.11 and later.
Installation
Install the latest release from PyPI:
python -m pip install sshreader
Quick start
Use SSH to run commands in a single SSH session. SSHreader can use an SSH key, an SSH agent, or a password:
from sshreader import SSH
with SSH("myhost.example.com", username="jdoe", keyfile="~/.ssh/id_ed25519") as ssh:
result = ssh.ssh_command("uname -a")
print(result.stdout)
print(result.return_code)
Use ServerJob and sshread to run jobs on multiple hosts. A job can contain multiple commands, which run sequentially on that host:
from sshreader import ServerJob, sshread
hosts = ["server1.example.com", "server2.example.com"]
jobs = [
ServerJob(host, ["hostname", "uptime"], username="jdoe", keyfile="~/.ssh/id_ed25519")
for host in hosts
]
finished_jobs = sshread(jobs, tcount=0)
for job in finished_jobs:
print(job.name, job.status)
for result in job.results:
print(result.cmd, result.stdout, result.stderr, result.return_code)
tcount=0 selects a thread count based on the available CPUs and number of jobs. Use pcount=0 to enable multiprocessing; you can also combine process and thread workers. When using multiprocessing, put the call to sshread inside the standard if __name__ == "__main__": guard.
Each command result has cmd, stdout, stderr, and return_code fields. A ServerJob stores its command results in results and the sum of their return codes in status.
Other features
- Run one or more commands over a reusable SSH connection with
SSH.ssh_command. - Transfer files over SFTP with
SSH.sftp_putandSSH.sftp_get. - Run local commands with
shell_command(shell-free by default; useshell=Trueonly when needed) or create localServerJobinstances withrun_local=True. - Use
Hookobjects to run functions before or after a job, including hooks that use its established SSH connection. - Discover the current username, SSH keys, and agent keys with
envvars(). - Configure connection and command timeouts, SSH ports, output handling, and worker counts.
See the documentation for detailed API guides and examples.
pydsh
Installing SSHreader also installs the pydsh command. It accepts hostlist expressions and runs a command across the expanded hosts:
pydsh -w 'web[01-10].example.com' 'uname -r'
By default, pydsh uses the current username and available SSH keys or agent, prompting for a password when needed. You can specify credentials and group or coalesce output:
pydsh -u jdoe -k ~/.ssh/id_ed25519 -D -w 'web[01-10].example.com' 'uname -r'
Use pydsh --help to see all options. With -F, the command argument is treated as a script file; the script must start with a shebang (#!), and --confirm skips the execution confirmation prompt.
Development
To set up a local development environment and run the tests:
uv sync --group test
uv run --group test pytest
Run lint and type checks with:
uv run --group test ruff check sshreader tests
uv run --group test ty check sshreader
Contributing
Bug reports, feature requests, and code contributions are welcome. Please open an issue with a minimal example and relevant traceback when reporting a problem. Contributions can be submitted as pull requests to the GitHub repository.
License
SSHreader is released under the GNU Lesser General Public License v3.0 or later. See LICENSE and LICENSE.lesser for the license texts.
Metadata
Release files for sshreader 7.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| sshreader-7.0.0.tar.gz | 38.9 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sshreader-7.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 74.9 kB
Release files / sshreader-7.0.0.tar.gz
| Download URL | sshreader-7.0.0.tar.gz |
|---|---|
| Size | 38.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7f53dcb17a68cb6b03ef62a7d2e39dc811fb6f16b924252537990c1306c5fb8d
|
|
BLAKE2b-256 checksum How to use checksums |
be8df94664ced5cf4491cfd8191b5839ef0e7e7475e0b74bf30515356c3d4a6f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.5 {"installer":{"name":"uv","version":"0.13.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / sshreader-7.0.0-py3-none-any.whl
| Download URL | sshreader-7.0.0-py3-none-any.whl |
|---|---|
| Size | 36.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c9e552ddec9b05ff6dad748187c3cb8ff741945974472f9e915c5ab952eb93e5
|
|
BLAKE2b-256 checksum How to use checksums |
978b32bb28e344ebbb5a962c3a834770c0627cc2bd98cf7dc45ef04dea3472fc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.5 {"installer":{"name":"uv","version":"0.13.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for sshreader 7.0.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.