Mpall //free\\ May 2026
import argparse import logging import sys import time import subprocess import signal import threading from concurrent.futures import ProcessPoolExecutor, as_completed from typing import List, Dict, Any, Optional, Tuple from dataclasses import dataclass, field from datetime import datetime import json import os
def parse_replacements(self) -> List[Dict[str, str]]: """Parse replacement arguments into list of parameter dictionaries.""" replacements = [] if self.args.replace_file: with open(self.args.replace_file, 'r') as f: for line in f: line = line.strip() if not line or line.startswith('#'): continue parts = line.split() if len(parts) < 2: self.logger.warning(f"Skipping invalid line: line") continue # Format: key1=val1 key2=val2 ... replacement = {} for part in parts: if '=' in part: k, v = part.split('=', 1) replacement[k] = v if replacement: replacements.append(replacement) elif self.args.replace: # Format: key1=val1,key2=val2 or multiple -r flags for rep in self.args.replace: rep_dict = {} for pair in rep.split(','): if '=' in pair: k, v = pair.split('=', 1) rep_dict[k] = v replacements.append(rep_dict) else: # Single run with no replacements replacements.append({}) return replacements import argparse import logging import sys import time
parser.add_argument( "--log-file", help="Save log to file" ) as_completed from typing import List
def debug(self, msg): self.logger.debug(msg) def info(self, msg): self.logger.info(msg) def warning(self, msg): self.logger.warning(msg) def error(self, msg): self.logger.error(msg) class CommandExecutor: """Executes shell commands with timeout and environment support.""" Tuple from dataclasses import dataclass
Save as `mpall.py`, make executable, and test:
def _print_summary(self, total_tasks: int, total_duration: float): """Print execution summary.""" succeeded = sum(1 for r in self.results if r.success) failed = total_tasks - succeeded self.logger.info("=" * 50) self.logger.info("SUMMARY") self.logger.info(f"Total tasks: total_tasks") self.logger.info(f"Succeeded: succeeded") self.logger.info(f"Failed: failed") self.logger.info(f"Total duration: total_duration:.2fs") if failed > 0: self.logger.info("\nFailed tasks:") for r in self.results: if not r.success: self.logger.info(f" Task r.task_id: r.stderr[:200]")