app
Component Widgets
Public Made by Adomby adom
Reusable component widgets for pinouts, thermal vias, molecule relationships, reviewed chip outlines and lightweight four-level LOD cache listings.
master
John Lauer
Add adom-verified, adom-models and adom-footprint-variants (moved from john/ pages) with their tools
7acd92d
16d ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
#!/usr/bin/env python3
"""Add a record to a component page's verification log (verification.json, schema adom/verification@1).
Run it inside a clone of the component page. Every --file is hashed (sha256) so the ::adom-verified widget
can tell readers, byte for byte, whether what was verified is still what the page serves.
verify_log.py add --by "John Lauer" --handle john --title "Footprint matches the datasheet" \\
--scope footprint --variant '*' --check "0.7 x 0.7 mm pads" --check "note:the datasheet gives no reason" \\
--evidence "pad proof=docs/img/pad-proof.png" --file WS2812B-2020.kicad_mod [--status open] [--date 2026-10-04]
verify_log.py variants --set "WS2812B-2020-V6=12 mA, 3.3-5.3 V" --stocked WS2812B-2020-V6
verify_log.py show
A check prefixed "fail:" or "note:" records that result; the default is pass."""
import argparse, datetime, hashlib, json, os, sys
PATH = "verification.json"
def load():
if os.path.exists(PATH): return json.load(open(PATH))
pj = json.load(open("page.json")) if os.path.exists("page.json") else {}
return {"schema": "adom/verification@1", "part": (pj.get("component") or {}).get("mpn") or pj.get("title"), "variants": [], "entries": []}
def save(d): json.dump(d, open(PATH, "w"), indent=1, ensure_ascii=False); open(PATH, "a").write("\n")
def main():
ap = argparse.ArgumentParser(); sub = ap.add_subparsers(dest="cmd", required=True)
a = sub.add_parser("add")
a.add_argument("--by", required=True); a.add_argument("--handle", default="")
a.add_argument("--title", required=True); a.add_argument("--status", default="verified", choices=["verified", "open", "superseded"])
a.add_argument("--date", default=datetime.date.today().isoformat())
a.add_argument("--scope", action="append", default=[]); a.add_argument("--variant", action="append", default=[])
a.add_argument("--check", action="append", default=[]); a.add_argument("--evidence", action="append", default=[])
a.add_argument("--file", action="append", default=[])
v = sub.add_parser("variants"); v.add_argument("--set", action="append", default=[]); v.add_argument("--stocked", action="append", default=[])
sub.add_parser("show")
o = ap.parse_args(); d = load()
if o.cmd == "add":
checks = []
for c in o.check:
res = "pass"
for p in ("fail:", "note:"):
if c.startswith(p): res, c = p[:-1], c[len(p):]
checks.append({"text": c.strip(), "result": res})
ev = [{"label": e.split("=", 1)[0], "href": e.split("=", 1)[1]} for e in o.evidence]
files = {}
for f in o.file:
if not os.path.exists(f): sys.exit("no such file: " + f)
files[f] = hashlib.sha256(open(f, "rb").read()).hexdigest()
d["entries"].append({"date": o.date, "by": {"name": o.by, "handle": o.handle}, "status": o.status, "title": o.title,
"scope": o.scope, "variants": o.variant or ["*"], "checks": checks, "evidence": ev, "files": files})
save(d); print(json.dumps({"entries": len(d["entries"]), "added": o.title, "files": len(files)}))
elif o.cmd == "variants":
by = {x["mpn"]: x for x in d["variants"]}
for s in o.set:
mpn, note = (s.split("=", 1) + [""])[:2]; by.setdefault(mpn, {"mpn": mpn})["note"] = note
for x in by.values(): x["stocked"] = x["mpn"] in o.stocked if o.stocked else x.get("stocked", False)
d["variants"] = list(by.values()); save(d); print(json.dumps(d["variants"]))
else:
print(json.dumps(d, indent=1))
if __name__ == "__main__":
main()