()
| 141 | |
| 142 | |
| 143 | def main(): |
| 144 | if not LEETGPU_API_KEY: |
| 145 | logger.error("LEETGPU_API_KEY environment variable is required") |
| 146 | return 1 |
| 147 | |
| 148 | parser = argparse.ArgumentParser() |
| 149 | parser.add_argument("path", type=Path, nargs="?") |
| 150 | args = parser.parse_args() |
| 151 | |
| 152 | if args.path: |
| 153 | dirs = [args.path] |
| 154 | else: |
| 155 | base = Path(__file__).parent.parent / "challenges" |
| 156 | dirs = [d for diff in base.iterdir() if diff.is_dir() for d in diff.iterdir() if d.is_dir()] |
| 157 | |
| 158 | # Load sequentially: load_challenge mutates sys.path/sys.modules and is not thread-safe. |
| 159 | payloads = [] |
| 160 | fail = 0 |
| 161 | for d in sorted(dirs): |
| 162 | try: |
| 163 | payloads.append(load_challenge(d)) |
| 164 | except Exception as e: |
| 165 | logger.error("Failed %s: %s", d, e) |
| 166 | fail += 1 |
| 167 | |
| 168 | # Upload in parallel: pure HTTP I/O, safe to run concurrently. |
| 169 | success = 0 |
| 170 | with ThreadPoolExecutor(max_workers=16) as executor: |
| 171 | futures = { |
| 172 | executor.submit(update_challenge, SERVICE_URL, p, LEETGPU_API_KEY): p for p in payloads |
| 173 | } |
| 174 | for future in as_completed(futures): |
| 175 | if future.result(): |
| 176 | success += 1 |
| 177 | else: |
| 178 | fail += 1 |
| 179 | |
| 180 | logger.info("Summary: %d succeeded, %d failed", success, fail) |
| 181 | return 0 if fail == 0 else 1 |
| 182 | |
| 183 | |
| 184 | if __name__ == "__main__": |
no test coverage detected