multiSSH3 5.83__py3-none-any.whl → 5.84__py3-none-any.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.
Potentially problematic release.
This version of multiSSH3 might be problematic. Click here for more details.
- multiSSH3.py +63 -16
- {multissh3-5.83.dist-info → multissh3-5.84.dist-info}/METADATA +1 -1
- multissh3-5.84.dist-info/RECORD +6 -0
- multissh3-5.83.dist-info/RECORD +0 -6
- {multissh3-5.83.dist-info → multissh3-5.84.dist-info}/WHEEL +0 -0
- {multissh3-5.83.dist-info → multissh3-5.84.dist-info}/entry_points.txt +0 -0
- {multissh3-5.83.dist-info → multissh3-5.84.dist-info}/top_level.txt +0 -0
multiSSH3.py
CHANGED
|
@@ -43,22 +43,48 @@ import tempfile
|
|
|
43
43
|
import math
|
|
44
44
|
from itertools import count
|
|
45
45
|
import queue
|
|
46
|
-
|
|
46
|
+
import typing
|
|
47
47
|
try:
|
|
48
48
|
# Check if functiools.cache is available
|
|
49
|
-
cache_decorator = functools.cache
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
49
|
+
# cache_decorator = functools.cache
|
|
50
|
+
def cache_decorator(user_function):
|
|
51
|
+
def _make_hashable(item):
|
|
52
|
+
if isinstance(item, typing.Mapping):
|
|
53
|
+
# Sort items so that {'a':1, 'b':2} and {'b':2, 'a':1} hash the same
|
|
54
|
+
return tuple(
|
|
55
|
+
( _make_hashable(k), _make_hashable(v) )
|
|
56
|
+
for k, v in sorted(item.items(), key=lambda item: item[0])
|
|
57
|
+
)
|
|
58
|
+
if isinstance(item, (list, set, tuple)):
|
|
59
|
+
return tuple(_make_hashable(e) for e in item)
|
|
60
|
+
# Fallback: assume item is already hashable
|
|
61
|
+
return item
|
|
62
|
+
def decorating_function(user_function):
|
|
63
|
+
# Create the real cached function
|
|
64
|
+
cached_func = functools.lru_cache(maxsize=None)(user_function)
|
|
65
|
+
@functools.wraps(user_function)
|
|
66
|
+
def wrapper(*args, **kwargs):
|
|
67
|
+
# Convert all args/kwargs to hashable equivalents
|
|
68
|
+
hashable_args = tuple(_make_hashable(a) for a in args)
|
|
69
|
+
hashable_kwargs = {
|
|
70
|
+
k: _make_hashable(v) for k, v in kwargs.items()
|
|
71
|
+
}
|
|
72
|
+
# Call the lru-cached version
|
|
73
|
+
return cached_func(*hashable_args, **hashable_kwargs)
|
|
74
|
+
# Expose cache statistics and clear method
|
|
75
|
+
wrapper.cache_info = cached_func.cache_info
|
|
76
|
+
wrapper.cache_clear = cached_func.cache_clear
|
|
77
|
+
return wrapper
|
|
78
|
+
return decorating_function(user_function)
|
|
79
|
+
except :
|
|
80
|
+
# If lrucache is not available, use a dummy decorator
|
|
81
|
+
print('Warning: functools.lru_cache is not available, multiSSH3 will run slower without cache.',file=sys.stderr)
|
|
82
|
+
def cache_decorator(func):
|
|
83
|
+
return func
|
|
84
|
+
version = '5.84'
|
|
59
85
|
VERSION = version
|
|
60
86
|
__version__ = version
|
|
61
|
-
COMMIT_DATE = '2025-07-
|
|
87
|
+
COMMIT_DATE = '2025-07-31'
|
|
62
88
|
|
|
63
89
|
CONFIG_FILE_CHAIN = ['./multiSSH3.config.json',
|
|
64
90
|
'~/multiSSH3.config.json',
|
|
@@ -264,6 +290,7 @@ class Host:
|
|
|
264
290
|
self.output_buffer = io.BytesIO()
|
|
265
291
|
self.stdout_buffer = io.BytesIO()
|
|
266
292
|
self.stderr_buffer = io.BytesIO()
|
|
293
|
+
self.thread = None
|
|
267
294
|
|
|
268
295
|
def __iter__(self):
|
|
269
296
|
return zip(['name', 'command', 'returncode', 'stdout', 'stderr'], [self.name, self.command, self.returncode, self.stdout, self.stderr])
|
|
@@ -386,6 +413,7 @@ __max_connections_nofile_limit_supported = 0
|
|
|
386
413
|
__thread_start_delay = 0
|
|
387
414
|
_encoding = DEFAULT_ENCODING
|
|
388
415
|
__returnZero = DEFAULT_RETURN_ZERO
|
|
416
|
+
__running_threads = set()
|
|
389
417
|
if __resource_lib_available:
|
|
390
418
|
# Get the current limits
|
|
391
419
|
_, __system_nofile_limit = resource.getrlimit(resource.RLIMIT_NOFILE)
|
|
@@ -580,6 +608,22 @@ def pretty_format_table(data, delimiter = '\t',header = None):
|
|
|
580
608
|
outTable.append(row_format.format(*row))
|
|
581
609
|
return '\n'.join(outTable) + '\n'
|
|
582
610
|
|
|
611
|
+
def join_threads(threads=__running_threads,timeout=None):
|
|
612
|
+
'''
|
|
613
|
+
Join threads
|
|
614
|
+
|
|
615
|
+
@params:
|
|
616
|
+
threads: The threads to join
|
|
617
|
+
timeout: The timeout
|
|
618
|
+
|
|
619
|
+
@returns:
|
|
620
|
+
None
|
|
621
|
+
'''
|
|
622
|
+
global __running_threads
|
|
623
|
+
for thread in threads:
|
|
624
|
+
thread.join(timeout=timeout)
|
|
625
|
+
if threads is __running_threads:
|
|
626
|
+
__running_threads = {t for t in threads if t.is_alive()}
|
|
583
627
|
#%% ------------ Compacting Hostnames ----------------
|
|
584
628
|
def __tokenize_hostname(hostname):
|
|
585
629
|
"""
|
|
@@ -1569,8 +1613,9 @@ def start_run_on_hosts(hosts, timeout=60,password=None,max_connections=4 * os.cp
|
|
|
1569
1613
|
return []
|
|
1570
1614
|
sem = threading.Semaphore(max_connections) # Limit concurrent SSH sessions
|
|
1571
1615
|
threads = [threading.Thread(target=run_command, args=(host, sem,timeout,password), daemon=True) for host in hosts]
|
|
1572
|
-
for thread in threads:
|
|
1616
|
+
for thread, host in zip(threads, hosts):
|
|
1573
1617
|
thread.start()
|
|
1618
|
+
host.thread = thread
|
|
1574
1619
|
time.sleep(__thread_start_delay)
|
|
1575
1620
|
return threads
|
|
1576
1621
|
|
|
@@ -2465,10 +2510,12 @@ def processRunOnHosts(timeout, password, max_connections, hosts, returnUnfinishe
|
|
|
2465
2510
|
eprint(f'Error writing to temporary file: {e!r}')
|
|
2466
2511
|
import traceback
|
|
2467
2512
|
eprint(traceback.format_exc())
|
|
2468
|
-
|
|
2513
|
+
if not called:
|
|
2514
|
+
print_output(hosts,json,greppable=greppable)
|
|
2515
|
+
else:
|
|
2516
|
+
__running_threads.update(threads)
|
|
2469
2517
|
# print the output, if the output of multiple hosts are the same, we aggragate them
|
|
2470
|
-
|
|
2471
|
-
print_output(hosts,json,greppable=greppable)
|
|
2518
|
+
|
|
2472
2519
|
|
|
2473
2520
|
#%% ------------ Stringfy Block ----------------
|
|
2474
2521
|
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
multiSSH3.py,sha256=-CzKDCUgMrgzmvtiLGgbQG0n_Gzk6IEqvUieLzJ29y0,154177
|
|
2
|
+
multissh3-5.84.dist-info/METADATA,sha256=9ZD6QwIhVXZXymckMv_aocvIzy2NHjyA_EnDaUhZn1s,18093
|
|
3
|
+
multissh3-5.84.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
4
|
+
multissh3-5.84.dist-info/entry_points.txt,sha256=xi2rWWNfmHx6gS8Mmx0rZL2KZz6XWBYP3DWBpWAnnZ0,143
|
|
5
|
+
multissh3-5.84.dist-info/top_level.txt,sha256=tUwttxlnpLkZorSsroIprNo41lYSxjd2ASuL8-EJIJw,10
|
|
6
|
+
multissh3-5.84.dist-info/RECORD,,
|
multissh3-5.83.dist-info/RECORD
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
multiSSH3.py,sha256=w0heb6yHP396yUahwNUN5s7MM9nvjB4TlkDW9vPL--g,152544
|
|
2
|
-
multissh3-5.83.dist-info/METADATA,sha256=I092cFBZ78N1k3CnYE2wzMX5Y2xjm3upVX6_G8sZURk,18093
|
|
3
|
-
multissh3-5.83.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
4
|
-
multissh3-5.83.dist-info/entry_points.txt,sha256=xi2rWWNfmHx6gS8Mmx0rZL2KZz6XWBYP3DWBpWAnnZ0,143
|
|
5
|
-
multissh3-5.83.dist-info/top_level.txt,sha256=tUwttxlnpLkZorSsroIprNo41lYSxjd2ASuL8-EJIJw,10
|
|
6
|
-
multissh3-5.83.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|