-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathaudit_example_graph.py
More file actions
executable file
·75 lines (63 loc) · 2.54 KB
/
Copy pathaudit_example_graph.py
File metadata and controls
executable file
·75 lines (63 loc) · 2.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#!/usr/bin/env python3
"""Audit see_also links as a lightweight example graph."""
from __future__ import annotations
import argparse
import sys
from collections import Counter
from _common import load_catalog
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument(
"--check",
action="store_true",
help="additionally fail on orphaned examples (invalid links, self-links, "
"and out-degree violations always fail)",
)
parser.add_argument("--max-out-degree", type=int, default=4)
args = parser.parse_args()
_catalog, examples = load_catalog()
slugs = {example["slug"] for example in examples}
incoming: Counter[str] = Counter()
outgoing: dict[str, list[str]] = {}
errors: list[str] = []
for example in examples:
slug = example["slug"]
links = list(example.get("see_also", []))
outgoing[slug] = links
if len(links) > args.max_out_degree:
errors.append(f"{slug}: too many see_also links ({len(links)} > {args.max_out_degree})")
if slug in links:
errors.append(f"{slug}: self-link")
for target in links:
if target not in slugs:
errors.append(f"{slug}: missing target {target}")
else:
incoming[target] += 1
linked = [slug for slug, links in outgoing.items() if links]
orphaned = sorted(slug for slug in slugs if not outgoing[slug] and incoming[slug] == 0)
high_in_degree = incoming.most_common(10)
reciprocal = []
for source, links in outgoing.items():
for target in links:
if source in outgoing.get(target, []):
reciprocal.append(tuple(sorted((source, target))))
reciprocal = sorted(set(reciprocal))
print(f"examples={len(examples)}")
print(f"linked_sources={len(linked)}")
print(f"edges={sum(len(links) for links in outgoing.values())}")
print(f"orphaned={len(orphaned)}")
if orphaned:
print("orphaned_slugs=" + ", ".join(orphaned[:25]) + (" ..." if len(orphaned) > 25 else ""))
if high_in_degree:
print("top_in_degree=" + ", ".join(f"{slug}:{count}" for slug, count in high_in_degree))
if reciprocal:
print("reciprocal_edges=" + ", ".join(f"{a}<->{b}" for a, b in reciprocal[:20]))
if args.check and orphaned:
errors.append("orphaned examples: " + ", ".join(orphaned))
if errors:
for error in errors:
print(error, file=sys.stderr)
return 1
return 0
if __name__ == "__main__":
raise SystemExit(main())