from __future__ import annotations import argparse import sys from pathlib import Path from .loading import Source, fetch_registry, local_source, registry_sources DEFAULT_VAULT = "https://vault1.magland.org" def _add_source_args(p: argparse.ArgumentParser) -> None: g = p.add_argument_group("solution sources (one of)") g.add_argument("--solutions", type=Path, help="a local directory containing /.json") g.add_argument("--registry", type=Path, help="registry JSON listing solution repositories") g.add_argument("--clones", type=Path, default=Path("clones"), help="where 'fetch' put the registered repositories") g.add_argument("--vault-url", default=DEFAULT_VAULT) def _sources(args) -> list[Source]: if args.solutions is not None and args.registry is not None: raise SystemExit("give either --solutions or --registry, not both") if args.solutions is not None: return [local_source(args.solutions)] if args.registry is not None: return registry_sources(args.registry, args.clones, args.vault_url) raise SystemExit("one of --solutions or --registry is required") def main(argv=None): ap = argparse.ArgumentParser(prog="challenge-tools", description="Validate submissions and build the comparison site.") sp = ap.add_subparsers(dest="cmd", required=True) f = sp.add_parser("fetch", help="clone or update the registered solution repositories") f.add_argument("--registry", required=True, type=Path) f.add_argument("--clones", type=Path, default=Path("clones")) f.add_argument("--vault-url", default=DEFAULT_VAULT) v = sp.add_parser("validate", help="check submission files and their outputs") v.add_argument("--challenges", required=True, type=Path, help="directory containing /challenge.json") _add_source_args(v) v.add_argument("--no-outputs", action="store_true", help="skip reading the wav and fields files") b = sp.add_parser("build", help="compute scores and write the static comparison site") b.add_argument("--challenges", required=True, type=Path) _add_source_args(b) b.add_argument("--out", required=True, type=Path) b.add_argument("--challenge-repo-url", default=None) args = ap.parse_args(argv) if args.cmd == "fetch": fetch_registry(args.registry, args.clones, args.vault_url) return 0 if args.cmd == "validate": from .validate import validate problems = validate(args.challenges, _sources(args), check_outputs=not args.no_outputs) for p in problems: print("PROBLEM:", p, file=sys.stderr) print(f"{len(problems)} problem(s)") return 1 if problems else 0 if args.cmd == "build": from .build import build from .validate import validate sources = _sources(args) problems = validate(args.challenges, sources) if problems: for p in problems: print("PROBLEM:", p, file=sys.stderr) return 1 results = build(args.challenges, sources, args.out, args.challenge_repo_url) for r in results: print(f"{r['challenge_id']}: {len(r['solutions'])} solutions, reference = {r['reference']}") for s in r["solutions"]: errs = " ".join(f"{k}={v:.3e}" for k, v in s["errors"].items()) print(f" {s['key']:50s} {errs} t={s['timing_seconds']}") return 0 return 2 if __name__ == "__main__": sys.exit(main())