multiCMD 1.15__py3-none-any.whl → 1.16__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.
- {multiCMD-1.15.dist-info → multiCMD-1.16.dist-info}/METADATA +25 -6
- multiCMD-1.16.dist-info/RECORD +7 -0
- multiCMD.py +37 -12
- multiCMD-1.15.dist-info/RECORD +0 -7
- {multiCMD-1.15.dist-info → multiCMD-1.16.dist-info}/LICENSE +0 -0
- {multiCMD-1.15.dist-info → multiCMD-1.16.dist-info}/WHEEL +0 -0
- {multiCMD-1.15.dist-info → multiCMD-1.16.dist-info}/entry_points.txt +0 -0
- {multiCMD-1.15.dist-info → multiCMD-1.16.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: multiCMD
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.16
|
4
4
|
Summary: Run commands simultaneously
|
5
5
|
Home-page: https://github.com/yufei-pan/multiCMD
|
6
6
|
Author: Yufei Pan
|
@@ -32,6 +32,10 @@ Can be used in bash scripts for automation actions.
|
|
32
32
|
|
33
33
|
Also able to be imported and act as a wrapper for subprocess.
|
34
34
|
|
35
|
+
Use return_object=True with run_commands or run_command to get the Task Object (definition below)
|
36
|
+
|
37
|
+
Use quiet=True and wait_for_return=False to create a daemon thread that async updates the return list / objects when return comes
|
38
|
+
|
35
39
|
For each process, it will initialize a thread if using -m/--max_threads > 1
|
36
40
|
|
37
41
|
For each thread, it will use subprocess lib to open a process for the command task
|
@@ -69,8 +73,9 @@ Run multiple commands in parallel
|
|
69
73
|
positional arguments:
|
70
74
|
command commands to run
|
71
75
|
|
72
|
-
|
76
|
+
options:
|
73
77
|
-h, --help show this help message and exit
|
78
|
+
-p, --parse Parse ranged input and expand them into multiple commands
|
74
79
|
-t timeout, --timeout timeout
|
75
80
|
timeout for each command
|
76
81
|
-m max_threads, --max_threads max_threads
|
@@ -81,12 +86,12 @@ optional arguments:
|
|
81
86
|
|
82
87
|
```python
|
83
88
|
def run_commands(commands, timeout=0,max_threads=1,quiet=False,dry_run=False,with_stdErr=False,
|
84
|
-
return_code_only=False,return_object=False):
|
89
|
+
return_code_only=False,return_object=False, parse = False, wait_for_return = True):
|
85
90
|
'''
|
86
91
|
Run multiple commands in parallel
|
87
92
|
|
88
93
|
@params:
|
89
|
-
commands: A list of commands to run
|
94
|
+
commands: A list of commands to run ( list[str] | list[list[str]] )
|
90
95
|
timeout: The timeout for each command
|
91
96
|
max_threads: The maximum number of threads to use
|
92
97
|
quiet: Whether to suppress output
|
@@ -94,12 +99,14 @@ def run_commands(commands, timeout=0,max_threads=1,quiet=False,dry_run=False,wit
|
|
94
99
|
with_stdErr: Whether to append the standard error output to the standard output
|
95
100
|
return_code_only: Whether to return only the return code
|
96
101
|
return_object: Whether to return the Task object
|
102
|
+
parse: Whether to parse ranged input
|
103
|
+
wait_for_return: Whether to wait for the return of the commands
|
97
104
|
|
98
105
|
@returns:
|
99
106
|
list: The output of the commands ( list[None] | list[int] | list[list[str]] | list[Task] )
|
100
|
-
|
107
|
+
'''
|
101
108
|
def run_command(command, timeout=0,max_threads=1,quiet=False,dry_run=False,with_stdErr=False,
|
102
|
-
return_code_only=False,return_object=False):
|
109
|
+
return_code_only=False,return_object=False,wait_for_return=True):
|
103
110
|
'''
|
104
111
|
Run a command
|
105
112
|
|
@@ -112,10 +119,22 @@ def run_command(command, timeout=0,max_threads=1,quiet=False,dry_run=False,with_
|
|
112
119
|
with_stdErr: Whether to append the standard error output to the standard output
|
113
120
|
return_code_only: Whether to return only the return code
|
114
121
|
return_object: Whether to return the Task object
|
122
|
+
wait_for_return: Whether to wait for the return of the command
|
115
123
|
|
116
124
|
@returns:
|
117
125
|
None | int | list[str] | Task: The output of the command
|
118
126
|
'''
|
127
|
+
def join_threads(threads=__running_threads,timeout=None):
|
128
|
+
'''
|
129
|
+
Join threads
|
130
|
+
|
131
|
+
@params:
|
132
|
+
threads: The threads to join
|
133
|
+
timeout: The timeout
|
134
|
+
|
135
|
+
@returns:
|
136
|
+
None
|
137
|
+
'''
|
119
138
|
def input_with_timeout_and_countdown(timeout, prompt='Please enter your selection'):
|
120
139
|
"""
|
121
140
|
Read an input from the user with a timeout and a countdown.
|
@@ -0,0 +1,7 @@
|
|
1
|
+
multiCMD.py,sha256=4sGtNKYAdZihHWtXbKHLaqLqJrnPVlEbhu8hbT2lxmw,16130
|
2
|
+
multiCMD-1.16.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
3
|
+
multiCMD-1.16.dist-info/METADATA,sha256=ZeWIRiZ6OhbiFwoVNxzgxxnxH6Q1HASXJSzOJqfI2sg,5758
|
4
|
+
multiCMD-1.16.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
5
|
+
multiCMD-1.16.dist-info/entry_points.txt,sha256=nSLBkYrcUCQxt1w3LIJkvgOhpRYEC0xAPqNG7u4OYs8,89
|
6
|
+
multiCMD-1.16.dist-info/top_level.txt,sha256=DSqgftD40G09F3qEjpHRCUNUsGUvGZZG69Sm3YEUiWI,9
|
7
|
+
multiCMD-1.16.dist-info/RECORD,,
|
multiCMD.py
CHANGED
@@ -11,9 +11,10 @@ import string
|
|
11
11
|
import re
|
12
12
|
import itertools
|
13
13
|
|
14
|
-
version = '1.
|
14
|
+
version = '1.16'
|
15
15
|
__version__ = version
|
16
16
|
|
17
|
+
__running_threads = []
|
17
18
|
class Task:
|
18
19
|
def __init__(self, command):
|
19
20
|
self.command = command
|
@@ -21,7 +22,11 @@ class Task:
|
|
21
22
|
self.stdout = []
|
22
23
|
self.stderr = []
|
23
24
|
def __iter__(self):
|
24
|
-
return zip(['command', 'returncode', 'stdout', 'stderr'], [self.
|
25
|
+
return zip(['command', 'returncode', 'stdout', 'stderr'], [self.command, self.returncode, self.stdout, self.stderr])
|
26
|
+
def __repr__(self):
|
27
|
+
return f'Task(command={self.command}, returncode={self.returncode}, stdout={self.stdout}, stderr={self.stderr})'
|
28
|
+
def __str__(self):
|
29
|
+
return str(dict(self))
|
25
30
|
|
26
31
|
def _expand_ranges(inStr):
|
27
32
|
'''
|
@@ -177,11 +182,11 @@ def __run_command(task,sem, timeout=60, quiet=False,dry_run=False,with_stdErr=Fa
|
|
177
182
|
#host.stdout = []
|
178
183
|
proc = subprocess.Popen(task.command,stdout=subprocess.PIPE,stderr=subprocess.PIPE,stdin=subprocess.PIPE)
|
179
184
|
# create a thread to handle stdout
|
180
|
-
stdout_thread = threading.Thread(target=__handle_stream, args=(proc.stdout,task.stdout,pre,post,quiet))
|
185
|
+
stdout_thread = threading.Thread(target=__handle_stream, args=(proc.stdout,task.stdout,pre,post,quiet),daemon=True)
|
181
186
|
stdout_thread.start()
|
182
187
|
# create a thread to handle stderr
|
183
188
|
#host.stderr = []
|
184
|
-
stderr_thread = threading.Thread(target=__handle_stream, args=(proc.stderr,task.stderr,pre,post,quiet))
|
189
|
+
stderr_thread = threading.Thread(target=__handle_stream, args=(proc.stderr,task.stderr,pre,post,quiet),daemon=True)
|
185
190
|
stderr_thread.start()
|
186
191
|
# Monitor the subprocess and terminate it after the timeout
|
187
192
|
start_time = time.time()
|
@@ -220,7 +225,7 @@ def __run_command(task,sem, timeout=60, quiet=False,dry_run=False,with_stdErr=Fa
|
|
220
225
|
return task.stdout
|
221
226
|
|
222
227
|
def run_command(command, timeout=0,max_threads=1,quiet=False,dry_run=False,with_stdErr=False,
|
223
|
-
return_code_only=False,return_object=False):
|
228
|
+
return_code_only=False,return_object=False,wait_for_return=True):
|
224
229
|
'''
|
225
230
|
Run a command
|
226
231
|
|
@@ -233,11 +238,14 @@ def run_command(command, timeout=0,max_threads=1,quiet=False,dry_run=False,with_
|
|
233
238
|
with_stdErr: Whether to append the standard error output to the standard output
|
234
239
|
return_code_only: Whether to return only the return code
|
235
240
|
return_object: Whether to return the Task object
|
241
|
+
wait_for_return: Whether to wait for the return of the command
|
236
242
|
|
237
243
|
@returns:
|
238
244
|
None | int | list[str] | Task: The output of the command
|
239
245
|
'''
|
240
|
-
return run_commands([command], timeout, max_threads, quiet,
|
246
|
+
return run_commands(commands=[command], timeout=timeout, max_threads=max_threads, quiet=quiet,
|
247
|
+
dry_run=dry_run, with_stdErr=with_stdErr, return_code_only=return_code_only,
|
248
|
+
return_object=return_object,parse=False,wait_for_return=wait_for_return)[0]
|
241
249
|
|
242
250
|
def __format_command(command,expand = False):
|
243
251
|
'''
|
@@ -275,9 +283,8 @@ def __format_command(command,expand = False):
|
|
275
283
|
else:
|
276
284
|
return __format_command(str(command),expand=expand)
|
277
285
|
|
278
|
-
|
279
286
|
def run_commands(commands, timeout=0,max_threads=1,quiet=False,dry_run=False,with_stdErr=False,
|
280
|
-
return_code_only=False,return_object=False, parse = False):
|
287
|
+
return_code_only=False,return_object=False, parse = False, wait_for_return = True):
|
281
288
|
'''
|
282
289
|
Run multiple commands in parallel
|
283
290
|
|
@@ -291,6 +298,7 @@ def run_commands(commands, timeout=0,max_threads=1,quiet=False,dry_run=False,wit
|
|
291
298
|
return_code_only: Whether to return only the return code
|
292
299
|
return_object: Whether to return the Task object
|
293
300
|
parse: Whether to parse ranged input
|
301
|
+
wait_for_return: Whether to wait for the return of the commands
|
294
302
|
|
295
303
|
@returns:
|
296
304
|
list: The output of the commands ( list[None] | list[int] | list[list[str]] | list[Task] )
|
@@ -304,13 +312,16 @@ def run_commands(commands, timeout=0,max_threads=1,quiet=False,dry_run=False,wit
|
|
304
312
|
# run the tasks with max_threads. if max_threads is 0, use the number of commands
|
305
313
|
if max_threads < 1:
|
306
314
|
max_threads = len(formatedCommands)
|
307
|
-
if max_threads > 1:
|
315
|
+
if max_threads > 1 or not wait_for_return:
|
308
316
|
sem = threading.Semaphore(max_threads) # Limit concurrent sessions
|
309
|
-
threads = [threading.Thread(target=__run_command, args=(task,sem,timeout,quiet,dry_run,...)) for task in tasks]
|
317
|
+
threads = [threading.Thread(target=__run_command, args=(task,sem,timeout,quiet,dry_run,...),daemon=True) for task in tasks]
|
310
318
|
for thread in threads:
|
311
319
|
thread.start()
|
312
|
-
|
313
|
-
thread
|
320
|
+
if wait_for_return:
|
321
|
+
for thread in threads:
|
322
|
+
thread.join()
|
323
|
+
else:
|
324
|
+
__running_threads.extend(threads)
|
314
325
|
else:
|
315
326
|
# just process the commands sequentially
|
316
327
|
sem = threading.Semaphore(1)
|
@@ -326,6 +337,20 @@ def run_commands(commands, timeout=0,max_threads=1,quiet=False,dry_run=False,wit
|
|
326
337
|
else:
|
327
338
|
return [task.stdout for task in tasks]
|
328
339
|
|
340
|
+
def join_threads(threads=__running_threads,timeout=None):
|
341
|
+
'''
|
342
|
+
Join threads
|
343
|
+
|
344
|
+
@params:
|
345
|
+
threads: The threads to join
|
346
|
+
timeout: The timeout
|
347
|
+
|
348
|
+
@returns:
|
349
|
+
None
|
350
|
+
'''
|
351
|
+
for thread in threads:
|
352
|
+
thread.join(timeout=timeout)
|
353
|
+
|
329
354
|
def input_with_timeout_and_countdown(timeout, prompt='Please enter your selection'):
|
330
355
|
"""
|
331
356
|
Read an input from the user with a timeout and a countdown.
|
multiCMD-1.15.dist-info/RECORD
DELETED
@@ -1,7 +0,0 @@
|
|
1
|
-
multiCMD.py,sha256=WlB4sRghGzDCPJOR-4ZRlykC-PattkPt67xv0cCQr7E,15268
|
2
|
-
multiCMD-1.15.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
3
|
-
multiCMD-1.15.dist-info/METADATA,sha256=jPEDesAqHHrgA3DagJKLbaHIqLZu3h2jDPHs-4eS5F0,5008
|
4
|
-
multiCMD-1.15.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
5
|
-
multiCMD-1.15.dist-info/entry_points.txt,sha256=nSLBkYrcUCQxt1w3LIJkvgOhpRYEC0xAPqNG7u4OYs8,89
|
6
|
-
multiCMD-1.15.dist-info/top_level.txt,sha256=DSqgftD40G09F3qEjpHRCUNUsGUvGZZG69Sm3YEUiWI,9
|
7
|
-
multiCMD-1.15.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|