sshreader 6.3.0__tar.gz → 7.0.0__tar.gz

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.
@@ -0,0 +1,131 @@
1
+ Metadata-Version: 2.1
2
+ Name: sshreader
3
+ Version: 7.0.0
4
+ Summary: Multi-threading/processing wrapper for Paramiko
5
+ Author-Email: Jesse Almanrode <jesse@almanrode.com>
6
+ License: LGPL-3.0-or-later
7
+ Classifier: Programming Language :: Python
8
+ Classifier: Intended Audience :: Developers
9
+ Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)
10
+ Classifier: Development Status :: 5 - Production/Stable
11
+ Classifier: Programming Language :: Python
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Programming Language :: Python :: 3.14
16
+ Classifier: Programming Language :: Python :: 3.15
17
+ Classifier: Topic :: Software Development :: Libraries
18
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
+ Project-URL: homepage, https://sshreader.readthedocs.io/
20
+ Project-URL: repository, https://github.com/isaiah1112/sshreader
21
+ Requires-Python: <4.0,>=3.11
22
+ Requires-Dist: click>=8.4.2
23
+ Requires-Dist: colorama>=0.4.6
24
+ Requires-Dist: paramiko>=5.0.0
25
+ Requires-Dist: progressbar2>=4.5.0
26
+ Requires-Dist: python-hostlist>=2.3.0
27
+ Description-Content-Type: text/markdown
28
+
29
+ ![SSHreader logo](./logo.png)
30
+
31
+ [![Python Tests](https://github.com/isaiah1112/sshreader/actions/workflows/lint_and_test.yml/badge.svg)](https://github.com/isaiah1112/sshreader/actions/workflows/lint_and_test.yml)
32
+
33
+ # SSHreader
34
+
35
+ SSHreader is a Python library for running commands on multiple servers in parallel. It wraps [Paramiko](https://www.paramiko.org/) 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.
36
+
37
+ SSHreader supports Python 3.11 and later.
38
+
39
+ ## Installation
40
+
41
+ Install the latest release from PyPI:
42
+
43
+ ```bash
44
+ python -m pip install sshreader
45
+ ```
46
+
47
+ ## Quick start
48
+
49
+ Use `SSH` to run commands in a single SSH session. SSHreader can use an SSH key, an SSH agent, or a password:
50
+
51
+ ```python
52
+ from sshreader import SSH
53
+
54
+ with SSH("myhost.example.com", username="jdoe", keyfile="~/.ssh/id_ed25519") as ssh:
55
+ result = ssh.ssh_command("uname -a")
56
+ print(result.stdout)
57
+ print(result.return_code)
58
+ ```
59
+
60
+ Use `ServerJob` and `sshread` to run jobs on multiple hosts. A job can contain multiple commands, which run sequentially on that host:
61
+
62
+ ```python
63
+ from sshreader import ServerJob, sshread
64
+
65
+ hosts = ["server1.example.com", "server2.example.com"]
66
+ jobs = [
67
+ ServerJob(host, ["hostname", "uptime"], username="jdoe", keyfile="~/.ssh/id_ed25519")
68
+ for host in hosts
69
+ ]
70
+
71
+ finished_jobs = sshread(jobs, tcount=0)
72
+ for job in finished_jobs:
73
+ print(job.name, job.status)
74
+ for result in job.results:
75
+ print(result.cmd, result.stdout, result.stderr, result.return_code)
76
+ ```
77
+
78
+ `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.
79
+
80
+ 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`.
81
+
82
+ ## Other features
83
+
84
+ - Run one or more commands over a reusable SSH connection with `SSH.ssh_command`.
85
+ - Transfer files over SFTP with `SSH.sftp_put` and `SSH.sftp_get`.
86
+ - Run local commands with `shell_command` (shell-free by default; use `shell=True` only when needed) or create local `ServerJob` instances with `run_local=True`.
87
+ - Use `Hook` objects to run functions before or after a job, including hooks that use its established SSH connection.
88
+ - Discover the current username, SSH keys, and agent keys with `envvars()`.
89
+ - Configure connection and command timeouts, SSH ports, output handling, and worker counts.
90
+
91
+ See the [documentation](https://sshreader.readthedocs.io/) for detailed API guides and examples.
92
+
93
+ ## `pydsh`
94
+
95
+ Installing SSHreader also installs the `pydsh` command. It accepts [hostlist expressions](https://pypi.org/project/python-hostlist/) and runs a command across the expanded hosts:
96
+
97
+ ```bash
98
+ pydsh -w 'web[01-10].example.com' 'uname -r'
99
+ ```
100
+
101
+ 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:
102
+
103
+ ```bash
104
+ pydsh -u jdoe -k ~/.ssh/id_ed25519 -D -w 'web[01-10].example.com' 'uname -r'
105
+ ```
106
+
107
+ 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.
108
+
109
+ ## Development
110
+
111
+ To set up a local development environment and run the tests:
112
+
113
+ ```bash
114
+ uv sync --group test
115
+ uv run --group test pytest
116
+ ```
117
+
118
+ Run lint and type checks with:
119
+
120
+ ```bash
121
+ uv run --group test ruff check sshreader tests
122
+ uv run --group test ty check sshreader
123
+ ```
124
+
125
+ ## Contributing
126
+
127
+ Bug reports, feature requests, and code contributions are welcome. Please [open an issue](https://github.com/isaiah1112/sshreader/issues) with a minimal example and relevant traceback when reporting a problem. Contributions can be submitted as pull requests to the [GitHub repository](https://github.com/isaiah1112/sshreader).
128
+
129
+ ## License
130
+
131
+ SSHreader is released under the [GNU Lesser General Public License v3.0 or later](https://www.gnu.org/licenses/lgpl-3.0.html). See [LICENSE](./LICENSE) and [LICENSE.lesser](./LICENSE.lesser) for the license texts.
@@ -0,0 +1,103 @@
1
+ ![SSHreader logo](./logo.png)
2
+
3
+ [![Python Tests](https://github.com/isaiah1112/sshreader/actions/workflows/lint_and_test.yml/badge.svg)](https://github.com/isaiah1112/sshreader/actions/workflows/lint_and_test.yml)
4
+
5
+ # SSHreader
6
+
7
+ SSHreader is a Python library for running commands on multiple servers in parallel. It wraps [Paramiko](https://www.paramiko.org/) 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.
8
+
9
+ SSHreader supports Python 3.11 and later.
10
+
11
+ ## Installation
12
+
13
+ Install the latest release from PyPI:
14
+
15
+ ```bash
16
+ python -m pip install sshreader
17
+ ```
18
+
19
+ ## Quick start
20
+
21
+ Use `SSH` to run commands in a single SSH session. SSHreader can use an SSH key, an SSH agent, or a password:
22
+
23
+ ```python
24
+ from sshreader import SSH
25
+
26
+ with SSH("myhost.example.com", username="jdoe", keyfile="~/.ssh/id_ed25519") as ssh:
27
+ result = ssh.ssh_command("uname -a")
28
+ print(result.stdout)
29
+ print(result.return_code)
30
+ ```
31
+
32
+ Use `ServerJob` and `sshread` to run jobs on multiple hosts. A job can contain multiple commands, which run sequentially on that host:
33
+
34
+ ```python
35
+ from sshreader import ServerJob, sshread
36
+
37
+ hosts = ["server1.example.com", "server2.example.com"]
38
+ jobs = [
39
+ ServerJob(host, ["hostname", "uptime"], username="jdoe", keyfile="~/.ssh/id_ed25519")
40
+ for host in hosts
41
+ ]
42
+
43
+ finished_jobs = sshread(jobs, tcount=0)
44
+ for job in finished_jobs:
45
+ print(job.name, job.status)
46
+ for result in job.results:
47
+ print(result.cmd, result.stdout, result.stderr, result.return_code)
48
+ ```
49
+
50
+ `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.
51
+
52
+ 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`.
53
+
54
+ ## Other features
55
+
56
+ - Run one or more commands over a reusable SSH connection with `SSH.ssh_command`.
57
+ - Transfer files over SFTP with `SSH.sftp_put` and `SSH.sftp_get`.
58
+ - Run local commands with `shell_command` (shell-free by default; use `shell=True` only when needed) or create local `ServerJob` instances with `run_local=True`.
59
+ - Use `Hook` objects to run functions before or after a job, including hooks that use its established SSH connection.
60
+ - Discover the current username, SSH keys, and agent keys with `envvars()`.
61
+ - Configure connection and command timeouts, SSH ports, output handling, and worker counts.
62
+
63
+ See the [documentation](https://sshreader.readthedocs.io/) for detailed API guides and examples.
64
+
65
+ ## `pydsh`
66
+
67
+ Installing SSHreader also installs the `pydsh` command. It accepts [hostlist expressions](https://pypi.org/project/python-hostlist/) and runs a command across the expanded hosts:
68
+
69
+ ```bash
70
+ pydsh -w 'web[01-10].example.com' 'uname -r'
71
+ ```
72
+
73
+ 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:
74
+
75
+ ```bash
76
+ pydsh -u jdoe -k ~/.ssh/id_ed25519 -D -w 'web[01-10].example.com' 'uname -r'
77
+ ```
78
+
79
+ 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.
80
+
81
+ ## Development
82
+
83
+ To set up a local development environment and run the tests:
84
+
85
+ ```bash
86
+ uv sync --group test
87
+ uv run --group test pytest
88
+ ```
89
+
90
+ Run lint and type checks with:
91
+
92
+ ```bash
93
+ uv run --group test ruff check sshreader tests
94
+ uv run --group test ty check sshreader
95
+ ```
96
+
97
+ ## Contributing
98
+
99
+ Bug reports, feature requests, and code contributions are welcome. Please [open an issue](https://github.com/isaiah1112/sshreader/issues) with a minimal example and relevant traceback when reporting a problem. Contributions can be submitted as pull requests to the [GitHub repository](https://github.com/isaiah1112/sshreader).
100
+
101
+ ## License
102
+
103
+ SSHreader is released under the [GNU Lesser General Public License v3.0 or later](https://www.gnu.org/licenses/lgpl-3.0.html). See [LICENSE](./LICENSE) and [LICENSE.lesser](./LICENSE.lesser) for the license texts.
@@ -2,16 +2,16 @@
2
2
  authors = [
3
3
  { name = "Jesse Almanrode", email = "jesse@almanrode.com" },
4
4
  ]
5
- requires-python = "<4.0,>3.9"
5
+ requires-python = ">=3.11,<4.0"
6
6
  dependencies = [
7
- "click<9,>=8",
8
- "colorama<1.0,>=0.4",
9
- "paramiko<4,>=3",
10
- "progressbar2<5,>=4",
11
- "python-hostlist<2,>=1",
7
+ "click>=8.4.2",
8
+ "colorama>=0.4.6",
9
+ "paramiko>=5.0.0",
10
+ "progressbar2>=4.5.0",
11
+ "python-hostlist>=2.3.0",
12
12
  ]
13
13
  name = "sshreader"
14
- version = "6.3.0"
14
+ version = "7.0.0"
15
15
  description = "Multi-threading/processing wrapper for Paramiko"
16
16
  readme = "README.md"
17
17
  classifiers = [
@@ -20,12 +20,11 @@ classifiers = [
20
20
  "License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)",
21
21
  "Development Status :: 5 - Production/Stable",
22
22
  "Programming Language :: Python",
23
- "Programming Language :: Python :: 3.9",
24
- "Programming Language :: Python :: 3.10",
25
23
  "Programming Language :: Python :: 3.11",
26
24
  "Programming Language :: Python :: 3.12",
27
25
  "Programming Language :: Python :: 3.13",
28
26
  "Programming Language :: Python :: 3.14",
27
+ "Programming Language :: Python :: 3.15",
29
28
  "Topic :: Software Development :: Libraries",
30
29
  "Topic :: Software Development :: Libraries :: Python Modules",
31
30
  ]
@@ -34,8 +33,8 @@ classifiers = [
34
33
  text = "LGPL-3.0-or-later"
35
34
 
36
35
  [project.urls]
37
- homepage = "http://sshreader.readthedocs.io/"
38
- repository = "https://bitbucket.org/isaiah1112/sshreader/"
36
+ homepage = "https://sshreader.readthedocs.io/"
37
+ repository = "https://github.com/isaiah1112/sshreader"
39
38
 
40
39
  [project.scripts]
41
40
  pydsh = "sshreader.scripts.pydsh:cli"
@@ -45,6 +44,9 @@ includes = [
45
44
  "sshreader",
46
45
  "sshreader/scripts",
47
46
  ]
47
+ excludes = [
48
+ "**/.DS_Store",
49
+ ]
48
50
 
49
51
  [tool.ruff.lint]
50
52
  select = [
@@ -75,11 +77,11 @@ build-backend = "pdm.backend"
75
77
 
76
78
  [dependency-groups]
77
79
  test = [
78
- "coverage<8,>=7",
79
- "discover<1.0,>=0.4",
80
- "pytest>=8.4.2",
81
- "ruff<1.0.0,>=0.9.9",
82
- "ty>=0.0.5",
80
+ "coverage>=7.15.2",
81
+ "discover>=0.4.0",
82
+ "pytest>=9.1.1",
83
+ "ruff>=0.15.22",
84
+ "ty>=0.0.60",
83
85
  ]
84
86
  docs = [
85
87
  "sphinx<8,>=7",
@@ -14,23 +14,23 @@
14
14
  #
15
15
  # You should have received a copy of the GNU Lesser General Public License
16
16
  # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
- from typing import NamedTuple, Optional, Union
17
+ from typing import NamedTuple
18
18
 
19
19
 
20
20
  class Command(NamedTuple):
21
21
  cmd: str
22
- stdout: Optional[Union[str, bytes]]
23
- stderr: Optional[Union[str, bytes]]
22
+ stdout: str | bytes | None
23
+ stderr: str | bytes | None
24
24
  return_code: int
25
25
 
26
26
 
27
27
  class EnvVars(NamedTuple):
28
- username: Optional[str]
29
- agent_keys: Optional[list]
30
- dsa_key: Optional[str]
31
- ecdsa_key: Optional[str]
32
- rsa_key: Optional[str]
28
+ username: str | None
29
+ agent_keys: list[object] | None
30
+ dsa_key: str | None
31
+ ecdsa_key: str | None
32
+ rsa_key: str | None
33
33
 
34
34
 
35
- Timeout = Union[int, float]
35
+ Timeout = int | float
36
36
  TimeoutTuple = tuple[Timeout, Timeout]