1
0
Files

83 lines
4.2 KiB
Python

#!/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:]))