speedtest-ssh 2.6.0__tar.gz → 2.6.2__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.
Files changed (22) hide show
  1. {speedtest_ssh-2.6.0/speedtest_ssh.egg-info → speedtest_ssh-2.6.2}/PKG-INFO +1 -1
  2. speedtest_ssh-2.6.2/speedtest_ssh/_version.py +1 -0
  3. {speedtest_ssh-2.6.0 → speedtest_ssh-2.6.2}/speedtest_ssh/data_transfer.py +16 -16
  4. speedtest_ssh-2.6.2/speedtest_ssh/ping.py +38 -0
  5. {speedtest_ssh-2.6.0 → speedtest_ssh-2.6.2}/speedtest_ssh/util.py +13 -0
  6. {speedtest_ssh-2.6.0 → speedtest_ssh-2.6.2/speedtest_ssh.egg-info}/PKG-INFO +1 -1
  7. speedtest_ssh-2.6.0/speedtest_ssh/_version.py +0 -1
  8. speedtest_ssh-2.6.0/speedtest_ssh/ping.py +0 -41
  9. {speedtest_ssh-2.6.0 → speedtest_ssh-2.6.2}/LICENSE +0 -0
  10. {speedtest_ssh-2.6.0 → speedtest_ssh-2.6.2}/README.md +0 -0
  11. {speedtest_ssh-2.6.0 → speedtest_ssh-2.6.2}/pyproject.toml +0 -0
  12. {speedtest_ssh-2.6.0 → speedtest_ssh-2.6.2}/setup.cfg +0 -0
  13. {speedtest_ssh-2.6.0 → speedtest_ssh-2.6.2}/speedtest_ssh/__init__.py +0 -0
  14. {speedtest_ssh-2.6.0 → speedtest_ssh-2.6.2}/speedtest_ssh/config.py +0 -0
  15. {speedtest_ssh-2.6.0 → speedtest_ssh-2.6.2}/speedtest_ssh/py.typed +0 -0
  16. {speedtest_ssh-2.6.0 → speedtest_ssh-2.6.2}/speedtest_ssh/sftp_wrapper.py +0 -0
  17. {speedtest_ssh-2.6.0 → speedtest_ssh-2.6.2}/speedtest_ssh/speedtest_ssh.py +0 -0
  18. {speedtest_ssh-2.6.0 → speedtest_ssh-2.6.2}/speedtest_ssh.egg-info/SOURCES.txt +0 -0
  19. {speedtest_ssh-2.6.0 → speedtest_ssh-2.6.2}/speedtest_ssh.egg-info/dependency_links.txt +0 -0
  20. {speedtest_ssh-2.6.0 → speedtest_ssh-2.6.2}/speedtest_ssh.egg-info/entry_points.txt +0 -0
  21. {speedtest_ssh-2.6.0 → speedtest_ssh-2.6.2}/speedtest_ssh.egg-info/requires.txt +0 -0
  22. {speedtest_ssh-2.6.0 → speedtest_ssh-2.6.2}/speedtest_ssh.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: speedtest_ssh
3
- Version: 2.6.0
3
+ Version: 2.6.2
4
4
  Summary: A tool meant to check inter-device speeds via ssh
5
5
  License: GPL
6
6
  Project-URL: Homepage, https://github.com/zwimer/speedtest_ssh
@@ -0,0 +1 @@
1
+ __version__: str = "2.6.2"
@@ -1,19 +1,18 @@
1
1
  from __future__ import annotations
2
+ from subprocess import CalledProcessError, PIPE
2
3
  from typing import TYPE_CHECKING
3
4
  from datetime import datetime
4
5
  from pathlib import Path
5
- import subprocess
6
6
  import random
7
7
  import string
8
- import shlex
9
8
  import re
10
9
  import os
11
10
 
12
11
  from tqdm import tqdm
13
12
 
14
13
  from .sftp_wrapper import sftp_wrapper
14
+ from .util import find_exe, run_cmd
15
15
  from .config import Config
16
- from .util import find_exe
17
16
 
18
17
  if TYPE_CHECKING:
19
18
  from paramiko import SFTPClient
@@ -52,20 +51,26 @@ class DataTransfer:
52
51
  :param config: The Config object the DataTransfer instance should use
53
52
  :param verbose: If true, be more verbose
54
53
  """
54
+ self._verbose = verbose
55
55
  rand = lambda: random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits)
56
56
  self._remote_f: str = f"/tmp/speedtest-ssh_{datetime.now()}_{''.join(rand() for _ in range(8))}.tmp"
57
57
  self._remote_f = self._remote_f.replace(":", "-").replace(" ", "_")
58
58
  # We promise that _remote_f components match: ^[a-zA-Z\d_.-]+$ (old rsync args suck)
59
+ if self._verbose:
60
+ print("Parsing ssh config and loading keys...")
59
61
  self._sftp_cm = sftp_wrapper(config)
60
62
  self._sftp: SFTPClient # Defined in __enter__
61
- self._verbose = verbose
62
63
 
63
64
  def __enter__(self) -> DataTransfer:
65
+ if self._verbose:
66
+ print("Establishing SFTP connection...")
64
67
  self._sftp = self._sftp_cm.__enter__()
65
68
  return self
66
69
 
67
70
  def __exit__(self, *args, **kwargs):
68
71
  self.clean_remote()
72
+ if self._verbose:
73
+ print("Terminating SFTP connection...")
69
74
  self._sftp_cm.__exit__(*args, **kwargs)
70
75
 
71
76
  def put(self, local: Path) -> None:
@@ -85,6 +90,8 @@ class DataTransfer:
85
90
  Removes the remote file
86
91
  """
87
92
  try:
93
+ if self._verbose:
94
+ print(f"Removing remote file (if it exists): {self._remote_f}")
88
95
  self._sftp.remove(self._remote_f)
89
96
  except FileNotFoundError:
90
97
  pass
@@ -120,13 +127,13 @@ class Rsync(DataTransfer):
120
127
  self._rsync = find_exe("rsync")
121
128
  # Determine rsync version
122
129
  try:
123
- output: str = self._run(self._rsync, "--version", stdout=subprocess.PIPE, check=True).stdout.decode()
124
- output = output.split("version")[1].split("protocol")[0].strip()
130
+ p = run_cmd(self._rsync, "--version", verbose=self._verbose, stdout=PIPE, check=True)
131
+ output = p.stdout.decode().split("version")[1].split("protocol")[0].strip()
125
132
  version: tuple[int, ...] = tuple(int(i) for i in output.split("."))
126
133
  self._old = version <= (3, 1, 0) # macOS has an old version by default
127
134
  if self._old:
128
135
  print("\tOld version of rsync detected. Output will be more verbose.")
129
- except (subprocess.CalledProcessError, KeyError) as e:
136
+ except (CalledProcessError, KeyError) as e:
130
137
  raise RuntimeError(f"Could not determine rsync version from {self._rsync}") from e
131
138
  # Determine rsync command
132
139
  self._flags: list[str | Path] = []
@@ -143,21 +150,14 @@ class Rsync(DataTransfer):
143
150
  # Determine host info
144
151
  self._target: str = ("" if config.user is None else f"{config.user}@") + f"{config.host}:{self._remote_f}"
145
152
 
146
- def _run(self, cmd: Path, *args: str | Path, **kwargs) -> subprocess.CompletedProcess:
147
- full = (cmd, *args)
148
- if self._verbose:
149
- msg = f"{'*'*30} Running Command: {cmd.name} {'*'*30}"
150
- print(f"{msg}\n{' '.join(shlex.quote(str(i)) for i in full)}\n{'*'*len(msg)}")
151
- return subprocess.run(full, **kwargs)
152
-
153
153
  def _transfer(self, src: str | Path, dst: str | Path) -> None:
154
154
  """
155
155
  :param src: The file to rsync to dst
156
156
  :param dst: The location to rsync src to
157
157
  """
158
158
  try:
159
- _ = self._run(self._rsync, *self._flags, src, dst, env=self._env, check=True)
160
- except subprocess.CalledProcessError as e:
159
+ _ = run_cmd(self._rsync, *self._flags, src, dst, verbose=self._verbose, env=self._env, check=True)
160
+ except CalledProcessError as e:
161
161
  raise RuntimeError("Failed to transfer data during speed test") from e
162
162
 
163
163
  def put(self, local: Path) -> None:
@@ -0,0 +1,38 @@
1
+ from subprocess import CalledProcessError, PIPE
2
+ from sys import platform
3
+
4
+ from .util import find_exe, run_cmd
5
+
6
+
7
+ __all__ = ("PingFailed", "ping")
8
+
9
+
10
+ class PingFailed(RuntimeError):
11
+ """
12
+ Raise on ping failure
13
+ """
14
+
15
+
16
+ def ping(host: str, verbose: bool, n_pings: int = 10, max_wait: int = 3) -> float:
17
+ """
18
+ :param host: The host to ping
19
+ :return: The number Ping host
20
+ """
21
+ # We use subprocess b/c ping is suid and we don't want to require root
22
+ print("Pinging...")
23
+ exe = find_exe("ping")
24
+ try:
25
+ wait: str = ("-W" if platform == "darwin" else "-w") + str(max_wait)
26
+ q = [] if verbose else ["-q"]
27
+ p = run_cmd(exe, "-i.1", f"-c{n_pings}", wait, *q, host, verbose=verbose, stdout=PIPE)
28
+ if p.returncode:
29
+ raise PingFailed(f"{exe} exit code: {p.returncode}")
30
+ output: str = p.stdout.decode().strip()
31
+ except CalledProcessError as e:
32
+ raise PingFailed("Unkown error") from e
33
+ if verbose:
34
+ print(output)
35
+ try:
36
+ return float(output.split("/")[-3])
37
+ except IndexError as e:
38
+ raise PingFailed("Bad output", output) from e
@@ -1,8 +1,13 @@
1
1
  from pathlib import Path
2
2
  from shutil import which
3
+ import subprocess
4
+ import shlex
3
5
  import os
4
6
 
5
7
 
8
+ __all__ = ("find_exe", "run_cmd")
9
+
10
+
6
11
  def find_exe(name: str) -> Path:
7
12
  """
8
13
  :param name: The name of the executable to find
@@ -15,3 +20,11 @@ def find_exe(name: str) -> Path:
15
20
  if not os.access(exe, os.X_OK):
16
21
  raise RuntimeError(f"Cannot find valid {name} executable")
17
22
  return exe
23
+
24
+
25
+ def run_cmd(cmd: Path, *args: str | Path, verbose: bool, **kwargs) -> subprocess.CompletedProcess:
26
+ full = (cmd, *args)
27
+ if verbose:
28
+ msg = f"{'*'*30} Running Command: {cmd.name} {'*'*30}"
29
+ print(f"{msg}\n{' '.join(shlex.quote(str(i)) for i in full)}\n{'*'*len(msg)}")
30
+ return subprocess.run(full, **kwargs)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: speedtest_ssh
3
- Version: 2.6.0
3
+ Version: 2.6.2
4
4
  Summary: A tool meant to check inter-device speeds via ssh
5
5
  License: GPL
6
6
  Project-URL: Homepage, https://github.com/zwimer/speedtest_ssh
@@ -1 +0,0 @@
1
- __version__: str = "2.6.0"
@@ -1,41 +0,0 @@
1
- from typing import TYPE_CHECKING
2
- from sys import platform
3
- import subprocess
4
-
5
- from .util import find_exe
6
-
7
- if TYPE_CHECKING:
8
- from pathlib import Path
9
-
10
-
11
- class PingFailed(RuntimeError):
12
- """
13
- Raise on ping failure
14
- """
15
-
16
-
17
- def ping(host: str, verbose: bool, n_pings: int = 10, max_wait: int = 3) -> float:
18
- """
19
- :param host: The host to ping
20
- :return: The number Ping host
21
- """
22
- # We use subprocess b/c ping is suid and we don't want to require root
23
- print("Pinging...")
24
- cmd: tuple[Path | str, ...] = (
25
- find_exe("ping"),
26
- "-i.1",
27
- f"-c{n_pings}",
28
- ("-W" if platform == "darwin" else "-w") + str(max_wait),
29
- *([] if verbose else ["-q"]),
30
- host,
31
- )
32
- try:
33
- output: str = subprocess.check_output(cmd).decode().strip()
34
- except subprocess.CalledProcessError as e:
35
- raise PingFailed("Non-zero exit code") from e
36
- if verbose:
37
- print(output)
38
- try:
39
- return float(output.split("/")[-3])
40
- except IndexError as e:
41
- raise PingFailed("Bad output", output) from e
File without changes
File without changes
File without changes