#!/usr/bin/env python3 """MK-Lemumi-as-Code pārbaudītājs. python3 tools/validate.py [data/…xml …] [--registry …] [--pasvaldibas …] [--valdibas …] Katrai sēdes datnei (pēc noklusējuma — visas data/lv-mk-sede-*.xml): - atbilst shēmai schemas/mk-lemumi-0.1.xsd (arī atslēgas: jautājumu, lēmumu un punktu identifikatori unikāli); - datnes nosaukums = sēdes identifikators; visi identifikatori sākas ar sēdes identifikatoru; - valdība ir valdību reģistrā; VPK ID — Valsts institūciju reģistrā; ATVK kods — Pašvaldību reģistrā; - katra lēmuma SourceFile ir repozitorijā, un katra punkta teksts tajā ir burtiski (rindā aiz punkta numura); - termiņa datums ir derīgs un teksts „līdz …” ir punkta tekstā. Reģistri pēc noklusējuma — no ProcessGit. """ import glob import os import sys from lxml import etree sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) import convert # noqa: E402 ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) N = {"m": convert.NS} def ids_of(xml, local, attr): return {e.get(attr) for e in etree.fromstring(xml).iter() if isinstance(e.tag, str) and etree.QName(e).localname == local} def main(argv): opt = {k: (argv[argv.index("--" + k) + 1] if "--" + k in argv else v) for k, v in convert.REG.items()} files = [a for a in argv if a.endswith(".xml") and a not in opt.values()] or sorted(glob.glob(os.path.join(ROOT, "data", "lv-mk-sede-*.xml"))) orgs = ids_of(convert.load(opt["registry"]), "Organization", "id") atvk = ids_of(convert.load(opt["pasvaldibas"]), "Municipality", "atvk") govs = ids_of(convert.load(opt["valdibas"]), "Government", "id") xsd = etree.XMLSchema(etree.parse(os.path.join(ROOT, "schemas", "mk-lemumi-0.1.xsd"))) errors, totals = [], [0, 0, 0] for path in files: tag = os.path.basename(path) doc = etree.parse(path) if not xsd.validate(doc): errors += [f"{tag}: XSD {e.line}: {e.message}" for e in list(xsd.error_log)[:10]] continue r = doc.getroot() mid = r.get("id") if tag != mid + ".xml": errors.append(f"{tag}: datnes nosaukumam jābūt {mid}.xml") if r.get("government") not in govs: errors.append(f"{tag}: valdība {r.get('government')} nav valdību reģistrā") for e in r.iter(): if isinstance(e.tag, str) and e.get("id") and e.get("id") != mid and not e.get("id").startswith(mid + "."): errors.append(f"{tag}: {e.get('id')} nesākas ar {mid}") if isinstance(e.tag, str) and e.get("org") and e.get("org") not in orgs: errors.append(f"{tag}: VPK ID {e.get('org')} nav Valsts institūciju reģistrā") if isinstance(e.tag, str) and e.get("atvk") and e.get("atvk") not in atvk: errors.append(f"{tag}: ATVK {e.get('atvk')} nav Pašvaldību reģistrā") for it in r.iterfind("m:Section/m:Item", N): totals[0] += 1 for d in it.iterfind("m:Decision", N): totals[1] += 1 src = os.path.join(ROOT, d.findtext("m:SourceFile", namespaces=N)) if not os.path.exists(src): errors.append(f"{tag}: {d.get('id')}: nav avota teksta {src}") continue lines = [ln.strip() for ln in open(src, encoding="utf-8")] for p in d.iter(f"{{{convert.NS}}}Point"): totals[2] += 1 want = ((p.get("n") + " ") if p.get("n") else "") + p.findtext("m:Text", namespaces=N) if want not in lines: errors.append(f"{tag}: {p.get('id')}: punkta teksts nav avota tekstā") dl = p.find("m:Deadline", N) if dl is not None and dl.text not in p.findtext("m:Text", namespaces=N): errors.append(f"{tag}: {p.get('id')}: termiņa teksts nav punktā") for e in errors: print("KĻŪDA", e) print(f"sēdes: {len(files)}, jautājumi: {totals[0]}, lēmumi: {totals[1]}, punkti: {totals[2]}, kļūdas: {len(errors)}") return 1 if errors else 0 if __name__ == "__main__": sys.exit(main(sys.argv[1:]))