ledger: github python org top-50 repos table + verifier
This commit is contained in:
1 parent
e101c60e49
commit
442cfe4443
2 files changed
+153
No files matched your search
@@ -0,0 +1,51 @@
|
||||
rank,repo,owner,description,language,stars,forks,open_issues,updated_at
|
||||
1,cpython,python,The Python programming language,Python,77750,38313,9417,2026-10-23T06:26:43Z
|
||||
2,mypy,python,Optional static typing for Python,Python,20695,3347,3224,2026-10-23T00:30:27Z
|
||||
3,typeshed,python,"Collection of library stubs for Python, with static types",Python,5135,2113,407,2026-10-23T04:08:08Z
|
||||
4,peps,python,Python Enhancement Proposals,reStructuredText,5029,1819,63,2026-10-22T15:59:15Z
|
||||
5,devguide,python,The Python developer's guide,Python,2112,1060,105,2026-10-23T06:24:34Z
|
||||
6,typing,python,Python static typing home. Hosts the documentation and a user help forum.,Python,1785,303,231,2026-10-23T00:57:03Z
|
||||
7,pythondotorg,python,Source code for python.org,Python,1667,708,22,2026-10-21T15:40:07Z
|
||||
8,asyncio,python,asyncio historical repository,,1083,179,86,2026-10-23T02:29:41Z
|
||||
9,pyperformance,python,Python Performance Benchmark Suite,Python,1041,205,76,2026-10-22T02:11:40Z
|
||||
10,typing_extensions,python,Backported and experimental type hints for Python,Python,590,152,23,2026-10-20T21:17:15Z
|
||||
11,python-docs-zh-cn,python,Simplified Chinese translation of the Python documentation,,468,106,6,2026-10-19T11:28:05Z
|
||||
12,python-docs-es,python,Spanish translation of the Python documentation.,Python,373,414,441,2026-10-20T14:22:42Z
|
||||
13,pymanager,python,The Python Install Manager (for Windows),Python,358,74,30,2026-10-23T05:42:17Z
|
||||
14,python-docs-fr,python,Mirroir de https://git.afpy.org/AFPy/python-docs-fr,,355,255,1,2026-10-17T12:23:33Z
|
||||
15,python-docs-zh-tw,python,Traditional Chinese (zh-tw) translation of the Python Documentation,Python,285,228,44,2026-10-15T20:32:21Z
|
||||
16,typed_ast,python,Modified fork of CPython's ast module that parses `# type:` comments,C,234,52,1,2026-08-27T10:32:57Z
|
||||
17,raspberryio,python,Source code for raspberry.io,Python,229,37,19,2026-08-27T10:32:52Z
|
||||
18,steering-council,python,Communications from the Steering Council,Makefile,182,35,11,2026-10-21T20:51:35Z
|
||||
19,python-docs-pt-br,python,Brazilian Portuguese translation of the Python Documentation,Python,165,42,17,2026-10-17T19:08:22Z
|
||||
20,mypy_extensions,python,Extensions for mypy,Python,155,41,8,2026-08-29T16:07:41Z
|
||||
21,planet,python,Configuration for Python planets,Python,144,197,33,2026-08-27T10:32:26Z
|
||||
22,importlib_metadata,python,Library to access metadata for Python packages,Python,142,100,17,2026-10-22T22:43:48Z
|
||||
23,bedevere,python,A bot to help identify missing information for CPython pull requests,Python,140,64,15,2026-10-21T18:37:46Z
|
||||
24,python-docs-tr,python,Turkish Translation of the Python Documentation,Python,128,47,34,2026-10-12T09:06:41Z
|
||||
25,psf-salt,python,PSF infrastructure configuration,Hurl,125,68,44,2026-10-22T14:49:24Z
|
||||
26,tzdata,python,Python package wrapping the IANA time zone database,Python,121,27,6,2026-10-20T17:43:29Z
|
||||
27,pycon-code-of-conduct,python,pycon code of conduct,,119,91,7,2026-10-02T15:15:25Z
|
||||
28,miss-islington,python,🐍🍒⛏🤖 - A bot for backporting and merging CPython pull requests,Python,116,43,4,2026-10-21T13:44:06Z
|
||||
29,pythoncapi-compat,python,The pythoncapi-compat project can be used to write a C extension supporting a wide range of Python versions with a single code base.,C++,112,41,2,2026-10-16T08:08:12Z
|
||||
30,core-workflow,python,Issue tracker for CPython's workflow,Python,104,57,9,2026-08-27T10:32:09Z
|
||||
31,python-docs-fa,python,Farsi (Persian) translation of the official Python documentation,Python,104,19,11,2026-10-23T05:29:32Z
|
||||
32,python-docs-theme,python,Sphinx theme for Python documentation,CSS,91,79,13,2026-10-17T08:27:16Z
|
||||
33,the-knights-who-say-ni,python,CLA enforcement bot for Python organization projects,Python,86,33,0,2026-09-18T23:32:31Z
|
||||
34,docsbuild-scripts,python,Scripts for building the documentation on docs.python.org,Python,84,70,8,2026-10-22T12:36:08Z
|
||||
35,python-docs-id,python,Terjemahan Bahasa Indonesia untuk Dokumentasi Python,Python,82,26,5,2026-10-22T00:27:22Z
|
||||
36,python-docs-ko,python,Korean translation of the Python documentation,,78,56,378,2026-10-14T08:40:48Z
|
||||
37,python-docs-ja,python,Japanese Translation of the Python Documentation,Python,75,38,1,2026-10-21T10:05:59Z
|
||||
38,importlib_resources,python,Backport of the importlib.resources module,Python,74,51,10,2026-10-21T20:41:18Z
|
||||
39,cherry-picker,python,🐍🍒⛏ Utility script for backporting/cherry-picking CPython changes from master into one of the maintenance branches.,Python,66,47,13,2026-10-06T18:00:06Z
|
||||
40,release-tools,python,Scripts for making (C)Python releases,Python,64,48,26,2026-10-22T20:47:47Z
|
||||
41,buildmaster-config,python,Configuration for buildbot.python.org,Python,61,62,10,2026-10-21T21:49:41Z
|
||||
42,python-docs-pl,python,Polskie tłumaczenie dokumentacji Pythona,Python,60,16,6,2026-10-22T10:26:03Z
|
||||
43,typing-council,python,Decisions by the Python Typing Council,,57,2,4,2026-10-15T14:13:32Z
|
||||
44,docs-community,python,Community management for documentation contributors and the Docs Workgroup,Makefile,55,28,22,2026-10-09T20:31:08Z
|
||||
45,community-starter-kit,python,Collection of resources for Python community organizers,Python,52,22,3,2026-09-09T01:53:00Z
|
||||
46,psf-chef,python,Chef configuration and cookbooks for the Python Software Foundation,Ruby,47,33,1,2026-08-27T10:32:28Z
|
||||
47,getpython3.com,python,getpython3.com page and resources.,CSS,46,14,8,2026-09-07T02:12:33Z
|
||||
48,codespeed,python,A fork of Codespeed that includes the instances run at https://speed.python.org/ and https://speed.pypy.org,Python,40,21,11,2026-08-27T10:32:06Z
|
||||
49,blurb_it,python,`blurb add` over the internet,Python,33,22,9,2026-10-22T01:00:02Z
|
||||
50,prebuilt-cpython,python,Repository for discussing/planning prebuilt binaries of CPython,Python,33,9,5,2026-10-22T23:57:44Z
|
||||
|
@@ -0,0 +1,102 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Verify the finished GitHub `python` org repos table (evidence test).
|
||||
|
||||
Input: /root/.hermes/wizard-outputs/ledger/python_org_repos_top50.csv
|
||||
Output: PASS line + exit 0, or FAIL + exit 1.
|
||||
|
||||
Checks:
|
||||
A. Schema/handshake of the stored CSV (exact header, 50 rows, unique
|
||||
repo names, ranks 1..50, integer counts >= 0, stars non-increasing).
|
||||
B. Stored top-50 equals a fresh fetch of the live GitHub API
|
||||
(independent source provenance, not the extractor's own output).
|
||||
"""
|
||||
import csv
|
||||
import json
|
||||
import sys
|
||||
import urllib.request
|
||||
|
||||
CSV_PATH = "/root/.hermes/wizard-outputs/ledger/python_org_repos_top50.csv"
|
||||
ORG = "python"
|
||||
PER_PAGE = 100
|
||||
N_TOP = 50
|
||||
EXPECTED_HEADER = ["rank", "repo", "owner", "description", "language",
|
||||
"stars", "forks", "open_issues", "updated_at"]
|
||||
HEADERS = {
|
||||
"Accept": "application/vnd.github+json",
|
||||
"X-GitHub-Api-Version": "2022-11-28",
|
||||
"User-Agent": "ledger-verify-python-org-repos/1.0",
|
||||
}
|
||||
|
||||
|
||||
def fetch_repos():
|
||||
page, all_repos = 1, []
|
||||
while True:
|
||||
url = "https://api.github.com/orgs/%s/repos?per_page=%d&page=%d" % (ORG, PER_PAGE, page)
|
||||
req = urllib.request.Request(url, headers=HEADERS)
|
||||
with urllib.request.urlopen(req, timeout=30) as r:
|
||||
all_repos.extend(json.loads(r.read()))
|
||||
link = r.getheader("Link") or ""
|
||||
if 'rel="next"' not in link:
|
||||
break
|
||||
page += 1
|
||||
return all_repos
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
with open(CSV_PATH, newline="", encoding="utf-8") as f:
|
||||
reader = csv.DictReader(f)
|
||||
header = reader.fieldnames
|
||||
rows = list(reader)
|
||||
except Exception as e:
|
||||
print("FAIL A: cannot read CSV: %s" % e)
|
||||
sys.exit(1)
|
||||
|
||||
if header != EXPECTED_HEADER:
|
||||
print("FAIL A: header mismatch: %r" % (header,))
|
||||
sys.exit(1)
|
||||
if len(rows) != N_TOP:
|
||||
print("FAIL A: expected %d rows, got %d" % (N_TOP, len(rows)))
|
||||
sys.exit(1)
|
||||
|
||||
names = [r["repo"] for r in rows]
|
||||
if len(set(names)) != N_TOP:
|
||||
print("FAIL A: duplicate repo names")
|
||||
sys.exit(1)
|
||||
if [int(r["rank"]) for r in rows] != list(range(1, N_TOP + 1)):
|
||||
print("FAIL A: ranks not contiguous 1..%d" % N_TOP)
|
||||
sys.exit(1)
|
||||
for r in rows:
|
||||
for c in ("stars", "forks", "open_issues"):
|
||||
try:
|
||||
v = int(r[c])
|
||||
except (TypeError, ValueError):
|
||||
print("FAIL A: %s not an integer: %r" % (c, r[c]))
|
||||
sys.exit(1)
|
||||
if v < 0:
|
||||
print("FAIL A: %s < 0: %s" % (c, v))
|
||||
sys.exit(1)
|
||||
stars = [int(r["stars"]) for r in rows]
|
||||
if stars != sorted(stars, reverse=True):
|
||||
print("FAIL A: stars not sorted non-increasing")
|
||||
sys.exit(1)
|
||||
|
||||
# Source provenance: recompute the top-50 from a fresh live fetch.
|
||||
live = fetch_repos()
|
||||
live_sorted = sorted(live, key=lambda r: (-int(r.get("stargazers_count") or 0),
|
||||
r["full_name"] or ""))
|
||||
live_top = live_sorted[:N_TOP]
|
||||
stored_top = [(r["repo"], int(r["stars"]), r["updated_at"]) for r in rows]
|
||||
live_top_t = [(r["name"], int(r["stargazers_count"] or 0), r["updated_at"])
|
||||
for r in live_top]
|
||||
if stored_top != live_top_t:
|
||||
print("FAIL B: stored table differs from a fresh live API fetch")
|
||||
sys.exit(1)
|
||||
|
||||
print("OK: %d rows verified against a fresh live GitHub API fetch (%d total repos fetched)"
|
||||
% (len(rows), len(live)))
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in new issue
Block a user