""" Seed Africa Centres of Excellence (ACE) as Community rows (unit_type="ace"), each minted a self-assigned persistent ID (PMD) — the same role ROR plays for institutions, minted locally via ark_generator (deterministic, no network access, idempotent on re-run). This script does NOT ship with any hardcoded ACE names — supply the real list at UNILAG (and any other institution) via a JSON input file: [ {"name": "ACE for Genomics of Non-Communicable Diseases", "institution": "unilag"}, {"name": "Another ACE Name", "institution": "unilag", "ror_id": "https://ror.org/..."} ] `institution` must match a short_name known to uraas/config/institutions.py. `ror_id` is optional — only set it if the ACE has been assigned its own ROR. Usage: python scripts/seed_ace_units.py ace_units.json # DRY RUN python scripts/seed_ace_units.py ace_units.json --apply """ import argparse import json import os import sys from datetime import datetime sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from uraas.config.institutions import get_registry from uraas.database import Community, SessionLocal from uraas.utils.ark_generator import ark_generator def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("input_file", help="JSON file listing ACE units to seed") parser.add_argument("--apply", action="store_true", help="Write changes (default: dry run)") args = parser.parse_args() with open(args.input_file, encoding="utf-8") as f: ace_units = json.load(f) if not isinstance(ace_units, list) or not ace_units: print("Input file must contain a non-empty JSON list of ACE units.") return 1 registry = get_registry() session = SessionLocal() try: planned = [] for entry in ace_units: name = entry.get("name") inst_short_name = entry.get("institution") if not name or not inst_short_name: print(f"SKIP (missing name/institution): {entry}") continue institution_config = registry.get(inst_short_name) if not institution_config: print(f"SKIP (unknown institution {inst_short_name!r}): {name}") continue existing = session.query(Community).filter_by(name=name).first() seed = f"ACE|{institution_config.ror}|{name}" pmd = ark_generator.mint(seed) planned.append((entry, institution_config, existing, pmd)) print("=" * 64) for entry, institution_config, existing, pmd in planned: status = "UPDATE" if existing else "CREATE" print(f"[{status}] {entry['name']} ({institution_config.name}) -> pmd={pmd}") print("=" * 64) print(f"{len(planned)} ACE unit(s) to process") if not args.apply: print("[DRY RUN] No writes. Re-run with --apply.") return 0 now = datetime.utcnow() created = updated = 0 for entry, institution_config, existing, pmd in planned: if existing: existing.unit_type = "ace" existing.institution = institution_config.name existing.ror = institution_config.ror if entry.get("ror_id"): existing.ror_id = entry["ror_id"] if not existing.pmd: existing.pmd = pmd existing.pmd_assigned_at = now updated += 1 else: community = Community( name=entry["name"], ror_id=entry.get("ror_id"), institution=institution_config.name, ror=institution_config.ror, unit_type="ace", pmd=pmd, pmd_assigned_at=now, ) session.add(community) created += 1 session.commit() print(f"DONE. Created: {created} Updated: {updated}") return 0 finally: session.close() if __name__ == "__main__": sys.exit(main())