multiCMD 1.44__tar.gz → 1.46__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: multiCMD
3
- Version: 1.44
3
+ Version: 1.46
4
4
  Summary: Run commands simultaneously
5
5
  Home-page: https://github.com/yufei-pan/multiCMD
6
6
  Author: Yufei Pan
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: multiCMD
3
- Version: 1.44
3
+ Version: 1.46
4
4
  Summary: Run commands simultaneously
5
5
  Home-page: https://github.com/yufei-pan/multiCMD
6
6
  Author: Yufei Pan
@@ -20,11 +20,12 @@ import subprocess
20
20
  import sys
21
21
  import threading
22
22
  import time
23
+ from pprint import pformat
23
24
 
24
25
  #%% global vars
25
- version = '1.44'
26
+ version = '1.46'
26
27
  __version__ = version
27
- COMMIT_DATE = '2026-01-13'
28
+ COMMIT_DATE = '2026-03-05'
28
29
  __running_threads = set()
29
30
  __variables = {}
30
31
 
@@ -45,16 +46,29 @@ class Task:
45
46
  self.stderr = []
46
47
  self.thread = None
47
48
  self.stop = False
49
+
48
50
  def __iter__(self):
49
- return zip(['command', 'returncode', 'stdout', 'stderr'], [self.command, self.returncode, self.stdout, self.stderr])
51
+ yield from (
52
+ ('command', self.command),
53
+ ('returncode', self.returncode),
54
+ ('stdout', self.stdout),
55
+ ('stderr', self.stderr)
56
+ )
57
+
50
58
  def __repr__(self):
51
- return f'Task(command={self.command}, returncode={self.returncode}, stdout={self.stdout}, stderr={self.stderr}, stop={self.stop})'
59
+ return f"""Task(command={pformat(self.command)},
60
+ returncode={self.returncode!r},
61
+ stdout=
62
+ {pformat(self.stdout)},
63
+ stderr=
64
+ {pformat(self.stderr)},
65
+ stop={self.stop!r})"""
66
+
52
67
  def __str__(self):
53
- return str(dict(self))
68
+ return pformat(dict(self))
69
+
54
70
  def is_alive(self):
55
- if self.thread is not None:
56
- return self.thread.is_alive()
57
- return False
71
+ return self.thread is not None and self.thread.is_alive()
58
72
 
59
73
  class AsyncExecutor:
60
74
  def __init__(self, max_threads=1,semaphore=...,timeout=0,quiet=True,dry_run=False,parse=False):
@@ -575,7 +589,8 @@ def ping(hosts,timeout=1,max_threads=0,quiet=True,dry_run=False,with_stdErr=Fals
575
589
  return results
576
590
 
577
591
  def run_command(command, timeout=0,max_threads=1,quiet=False,dry_run=False,with_stdErr=False,
578
- return_code_only=False,return_object=False,wait_for_return=True, sem = None):
592
+ return_code_only=False,return_object=False,wait_for_return=True, sem = None,
593
+ use_sudo = ..., raise_error = False):
579
594
  '''
580
595
  Run a command
581
596
 
@@ -590,17 +605,20 @@ def run_command(command, timeout=0,max_threads=1,quiet=False,dry_run=False,with_
590
605
  return_object: Whether to return the Task object
591
606
  wait_for_return: Whether to wait for the return of the command
592
607
  sem: The semaphore to use for threading
608
+ use_sudo: Whether to use sudo for commands
609
+ raise_error: Whether to raise an error if the command fails
593
610
 
594
611
  @returns:
595
612
  None | int | list[str] | Task: The output of the command
596
613
  '''
597
614
  return run_commands(commands=[command], timeout=timeout, max_threads=max_threads, quiet=quiet,
598
615
  dry_run=dry_run, with_stdErr=with_stdErr, return_code_only=return_code_only,
599
- return_object=return_object,parse=False,wait_for_return=wait_for_return,sem=sem)[0]
616
+ return_object=return_object,parse=False,wait_for_return=wait_for_return,sem=sem,
617
+ use_sudo=use_sudo, raise_error=raise_error)[0]
600
618
 
601
619
  def run_commands(commands, timeout=0,max_threads=1,quiet=False,dry_run=False,with_stdErr=False,
602
620
  return_code_only=False,return_object=False, parse = False, wait_for_return = True,
603
- sem : threading.Semaphore = None, use_sudo=...):
621
+ sem : threading.Semaphore = None, use_sudo=..., raise_error = False):
604
622
  '''
605
623
  Run multiple commands in parallel
606
624
 
@@ -616,9 +634,11 @@ def run_commands(commands, timeout=0,max_threads=1,quiet=False,dry_run=False,wit
616
634
  parse: Whether to parse ranged input
617
635
  wait_for_return: Whether to wait for the return of the commands
618
636
  sem: The semaphore to use for threading
637
+ use_sudo: Whether to use sudo for commands
638
+ raise_error: Whether to raise an error if the command fails
619
639
 
620
640
  @returns:
621
- list: The output of the commands ( list[None] | list[int] | list[list[str]] | list[Task] )
641
+ list: The output of the commands ( list[None] | list[int] | list[list[str]] | list[Task] | None )
622
642
  '''
623
643
  global USE_SUDO
624
644
  global SUDO_PATH
@@ -654,6 +674,10 @@ def run_commands(commands, timeout=0,max_threads=1,quiet=False,dry_run=False,wit
654
674
  for task in tasks:
655
675
  __run_command(task,sem,timeout,quiet,dry_run,identity=None)
656
676
  # return the only the output for the tasks
677
+ if raise_error:
678
+ errors = [task for task in tasks if task.returncode != 0]
679
+ if errors:
680
+ raise Exception(f"Commands failed: {pformat(errors)}")
657
681
  if return_code_only:
658
682
  return [task.returncode for task in tasks]
659
683
  elif return_object:
File without changes
File without changes
File without changes