Run tasks in parallel and print results as each task finishes. Args: tasks: List of (name, spec) pairs. verbose: If True, print output even for successful tasks. print_duration: If True, include duration in status lines. spinner_suffix: Suffix after the count in
(
tasks: list[tuple[str, TaskSpec]],
verbose: bool = False,
print_duration: bool = True,
spinner_suffix: str = "tasks",
print_summary: bool = True,
)
| 129 | |
| 130 | |
| 131 | def run_parallel( |
| 132 | tasks: list[tuple[str, TaskSpec]], |
| 133 | verbose: bool = False, |
| 134 | print_duration: bool = True, |
| 135 | spinner_suffix: str = "tasks", |
| 136 | print_summary: bool = True, |
| 137 | ) -> list[str]: |
| 138 | """Run tasks in parallel and print results as each task finishes. |
| 139 | |
| 140 | Args: |
| 141 | tasks: List of (name, spec) pairs. |
| 142 | verbose: If True, print output even for successful tasks. |
| 143 | print_duration: If True, include duration in status lines. |
| 144 | spinner_suffix: Suffix after the count in the spinner, e.g. "tasks". |
| 145 | print_summary: If True, print a final success/failure summary. |
| 146 | |
| 147 | Returns: |
| 148 | List of failed task names (empty on full success). |
| 149 | """ |
| 150 | done_q: queue.Queue[TaskThread] = queue.Queue() |
| 151 | threads = [TaskThread(name, spec, done_queue=done_q) for name, spec in tasks] |
| 152 | |
| 153 | spinner = _SpinnerThread(len(threads), spinner_suffix) |
| 154 | spinner.start() |
| 155 | |
| 156 | for t in threads: |
| 157 | t.start() |
| 158 | |
| 159 | failed = [] |
| 160 | for _ in threads: |
| 161 | t = done_q.get() |
| 162 | spinner.task_done() |
| 163 | spinner.clear_line() |
| 164 | formatted_duration = ( |
| 165 | f" [{t.duration.total_seconds():5.2f}s]" if print_duration else "" |
| 166 | ) |
| 167 | if t.success: |
| 168 | print(f"{_prefix('---')}{OK}{formatted_duration} {t.name}") |
| 169 | else: |
| 170 | print(f"{_prefix('+++')}{FAIL}{formatted_duration} {t.name}") |
| 171 | failed.append(t.name) |
| 172 | if t.output and (not t.success or verbose): |
| 173 | print(t.output) |
| 174 | |
| 175 | spinner.stop() |
| 176 | |
| 177 | if print_summary: |
| 178 | if failed: |
| 179 | print(f"{_prefix('+++')}{FAIL} Failed: {failed}") |
| 180 | else: |
| 181 | print(f"{_prefix('+++')}{OK} All tasks successful") |
| 182 | |
| 183 | return failed |
no test coverage detected