#!/usr/bin/env python3 """Fetch the top 20 most-starred public Python repos and write the artifact.""" import json import urllib.request import urllib.parse from datetime import datetime, timezone OUT = "/root/.hermes/wizard-outputs/ledger/python-repos-top20.json" CSV_OUT = "/root/.hermes/wizard-outputs/ledger/python-repos-top20.csv" QUERY = "language:python" PAGE = 20 def fetch(url): req = urllib.request.Request(url, headers={"User-Agent": "ledger-wizard"}) with urllib.request.urlopen(req, timeout=60) as r: return json.loads(r.read().decode("utf-8")) def main(): q = urllib.parse.quote(QUERY) url = f"https://api.github.com/search/repositories?q={q}&sort=stars&order=desc&per_page={PAGE}" data = fetch(url) items = data.get("items", []) # search API returns already-ordered by stars desc; we still enforce order. rows = [] for i, it in enumerate(items, start=1): rows.append({ "rank": i, "name": it["name"], "full_name": it["full_name"], "owner": it["owner"]["login"], "stars": it["stargazers_count"], "url": it["html_url"], "description": (it.get("description") or "").replace("\n", " ")[:400], }) payload = { "source": "https://api.github.com/search/repositories", "query": f"language:python sort:stars order:desc per_page={PAGE}", "total_count": data.get("total_count"), "incomplete_results": data.get("incomplete_results"), "fetched_at": datetime.now(timezone.utc).isoformat(), "rows": rows, } with open(OUT, "w", encoding="utf-8") as f: json.dump(payload, f, indent=2) with open(CSV_OUT, "w", encoding="utf-8") as f: f.write("rank,name,owner,stars,url,description\n") for r in rows: desc = r["description"].replace(",", " ").replace("\n", " ") f.write(f'{r["rank"]},{r["name"]},{r["owner"]},{r["stars"]},{r["url"]},{desc}\n') print(f"wrote {OUT}") print(f"wrote {CSV_OUT}") print(f"total_count={payload['total_count']} rows={len(rows)} top_stars={rows[0]['stars']}") print("top:", rows[0]["full_name"], rows[0]["stars"]) if __name__ == "__main__": main()