|
57 | 57 | import multiprocessing |
58 | 58 | import re |
59 | 59 | import sys |
60 | | -from collections.abc import Generator, Sequence |
| 60 | +from collections.abc import Generator, Mapping, Sequence |
61 | 61 | from dataclasses import dataclass |
62 | 62 | from datetime import timedelta |
63 | 63 | from functools import partial |
64 | 64 | from textwrap import dedent |
| 65 | +from typing import Literal |
65 | 66 |
|
66 | 67 | import click |
67 | 68 | import structlog |
@@ -101,9 +102,8 @@ class GenerateSettings: |
101 | 102 |
|
102 | 103 | # pylint: disable=broad-except |
103 | 104 | def generate_report( |
104 | | - item: tuple[str, GenerateSettings, str], |
| 105 | + product_name: str, settings: GenerateSettings, grouping_time_zone: str |
105 | 106 | ) -> tuple[str, GenerateResult, TimePeriodOverview | None]: |
106 | | - product_name, settings, grouping_time_zone = item |
107 | 107 | log = _LOG.bind(product=product_name) |
108 | 108 |
|
109 | 109 | started_years = set() |
@@ -173,43 +173,35 @@ def run_generation( |
173 | 173 |
|
174 | 174 | user_message("Generating product summaries...") |
175 | 175 |
|
176 | | - def on_complete( |
177 | | - product_name: str, result: GenerateResult, summary: TimePeriodOverview | None |
178 | | - ) -> None: |
179 | | - counts[result] += 1 |
180 | | - result_color = { |
181 | | - GenerateResult.ERROR: "red", |
182 | | - GenerateResult.UNSUPPORTED: "yellow", |
183 | | - GenerateResult.CREATED: "blue", |
184 | | - GenerateResult.UPDATED: "green", |
185 | | - }.get(result) |
186 | | - extra = "" |
187 | | - if summary is not None: |
188 | | - extra = f" (contains {summary.dataset_count} total datasets)" |
| 176 | + color: Mapping[GenerateResult, Literal["red", "yellow", "blue", "green"]] = { |
| 177 | + GenerateResult.ERROR: "red", |
| 178 | + GenerateResult.UNSUPPORTED: "yellow", |
| 179 | + GenerateResult.CREATED: "blue", |
| 180 | + GenerateResult.UPDATED: "green", |
| 181 | + } |
189 | 182 |
|
190 | | - user_message( |
191 | | - f"{style(product_name, fg=result_color)} {result.name.lower()}{extra}" |
192 | | - ) |
193 | | - |
194 | | - # If one worker, avoid any subprocesses/forking. |
195 | | - # This makes test tracing far easier. |
196 | | - if workers == 1: |
197 | | - for p in products: |
198 | | - on_complete(*generate_report((p.name, settings, grouping_time_zone))) |
199 | | - else: |
200 | | - # Shut down pool nicely to keep pytest-cov happy. |
201 | | - # https://pytest-cov.readthedocs.io/en/latest/subprocess-support.html#if-you-use-multiprocessing-pool |
202 | | - pool = multiprocessing.Pool(workers) |
203 | | - try: |
204 | | - for product_name, result, summary in pool.imap_unordered( |
205 | | - generate_report, |
206 | | - ((p.name, settings, grouping_time_zone) for p in products), |
207 | | - chunksize=1, |
208 | | - ): |
209 | | - on_complete(product_name, result, summary) |
210 | | - finally: |
211 | | - pool.close() |
212 | | - pool.join() |
| 183 | + # Shut down pool nicely to keep pytest-cov happy. |
| 184 | + # https://pytest-cov.readthedocs.io/en/latest/subprocess-support.html#if-you-use-multiprocessing-pool |
| 185 | + pool = multiprocessing.Pool(workers) |
| 186 | + try: |
| 187 | + results = [ |
| 188 | + pool.apply_async(generate_report, (p.name, settings, grouping_time_zone)) |
| 189 | + for p in products |
| 190 | + ] |
| 191 | + for res in results: |
| 192 | + product_name, result, summary = res.get() |
| 193 | + counts[result] += 1 |
| 194 | + extra = ( |
| 195 | + "" |
| 196 | + if summary is None |
| 197 | + else f" (contains {summary.dataset_count} total datasets)" |
| 198 | + ) |
| 199 | + user_message( |
| 200 | + f"{style(product_name, fg=color.get(result))} {result.name.lower()}{extra}" |
| 201 | + ) |
| 202 | + finally: |
| 203 | + pool.close() |
| 204 | + pool.join() |
213 | 205 |
|
214 | 206 | status_messages = ", ".join( |
215 | 207 | f"{count_} {status.name.lower()}" for status, count_ in counts.items() |
|
0 commit comments