diff --git a/CHANGELOG.md b/CHANGELOG.md index 58c3d61..f479c87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Izmaiņas +## 0.1.1 — 2026-10-11 + +- Labots: 68. lappusē uzdevumu [315]–[318] teksta pirmie vārdi bija nonākuši ailē „Nr.” un datnē trūka; indikatora [219] + nosaukumā trūka „2.”. Pārbaudei pievienota apgrieztā pārbaude — katrs avotā drukātais tabulas rindas vārds ir datnē. +- Labots: atsevišķi vārdi, ko PDF bija sadalījis (piem., „Neprognozējama”, „Olimpiskajā”), un zemsvītras piezīme 9. +- Jauns atribūts `currentOrg`, `currentSince` uzdevuma institūcijai: septiņiem VARAM uzdevumiem — Klimata un enerģētikas + ministrija (klimata politika no 2023-01-01, vides aizsardzības politika no 2024-07-01). + ## 0.1.0 — 2026-10-11 - Shēma `schemas/strategija-0.1.xsd` attīstības plānošanas dokumentiem: nodaļas, numurētie punkti ar veidu, indikatori, diff --git a/README.md b/README.md index 8f8f7e1..7efa7ec 100644 --- a/README.md +++ b/README.md @@ -62,9 +62,17 @@ Sasaiste ir `sources/nap2027/dalibnieki.yaml`; elementā `Actors` katram apzīm | `assumed` | Apzīmējums nav dokumenta saīsinājumu sarakstā; nozīme pieņemta | LTKR (→ LTRK), LABS (→ LBAS), LIZDA, LLPA | | `none` | Nav valsts institūcija | Nasdaq | -Uzdevumi saista institūciju, kas norādīta apstiprinātajā dokumentā. Ja funkcija vēlāk pārcelta citai institūcijai -(piemēram, vides aizsardzības politika no VARAM uz Klimata un enerģētikas ministriju 2024. gadā), datnē paliek dokumentā -norādītā institūcija; pārmaiņa ir reģistrā. +Uzdevumi saista institūciju, kas norādīta apstiprinātajā dokumentā (`org`). Ja uzdevuma jomu vēlāk pārņēmusi cita +institūcija, tā norādīta papildus (`currentOrg`, `currentSince`). NAP2027 tas attiecas uz septiņiem VARAM uzdevumiem rīcības +virzienā „Daba un vide – „Zaļais kurss”” — tagad Klimata un enerģētikas ministrija (`20-0000`): + +| Uzdevumi | Joma | Kopš | +|---|---|---| +| [281], [282] | Klimata politika | 2023-01-01 | +| [283], [284], [285], [287], [288] | Vides aizsardzības politika (gaiss, ūdeņi, aprites ekonomika, atkritumi, piesārņotās vietas) | 2024-07-01 | + +Bioloģiskās daudzveidības uzdevumi [289]–[291] paliek VARAM (dabas aizsardzība netika nodota). Zemes dzīļu [286] un +sabiedrības izpratnes par vidi [292] uzdevumiem pašreizējā institūcija nav norādīta. ## Uzdevumu indikatori @@ -83,7 +91,8 @@ python3 tools/validate.py Pārbaude izmanto citu PDF nolasītāju (poppler `pdftotext`) nekā datnes veidošana: katrs drukātais numurs datnē ir tieši vienreiz; teksta punktu un pamatojuma punktu burti ir avota tekstā (dažiem — 2–4 daļās, jo avota lasīšanas secībā starp -tām ir zemsvītras piezīme vai tabulas aile); katrs tabulas rindas vārds (9684) ir avotā starp punkta numuru un nākamo numuru; +tām ir zemsvītras piezīme vai tabulas aile); katrs tabulas rindas vārds ir avotā starp punkta numuru un nākamo numuru, +un otrādi — katrs avotā drukātais rindas vārds ir datnē; katram uzdevumam ir atbildīgā institūcija ar VPK ID; katram indikatoram — vērtības. ## Datu kopa VDZP diff --git a/data/nap2027/lv-nap2027.xml b/data/nap2027/lv-nap2027.xml index a59993b..0706079 100644 --- a/data/nap2027/lv-nap2027.xml +++ b/data/nap2027/lv-nap2027.xml @@ -26,6 +26,7 @@ Pirmā versija: 475 numurētie punkti [1]–[475], 154 pamatojuma punkti, 34 zemsvītras piezīmes, 66 saīsinājumi. Atbildīgās un līdzatbildīgās institūcijas sasaistītas ar VPK ID; drukātais apzīmējums saglabāts. + Uzdevumiem, kuru jomu pārņēmusi Klimata un enerģētikas ministrija (klimata politika no 2023-01-01, vides aizsardzības politika no 2024-07-01), pie VARAM norādīta pašreizējā institūcija (currentOrg). @@ -2631,7 +2632,7 @@ - Parāda apkalpošanas maksājumu attiecība pret ienākumiem ienākumu kvintilē + Parāda apkalpošanas maksājumu attiecība pret ienākumiem 2. ienākumu kvintilē % 2018 34,1 @@ -2730,7 +2731,7 @@ Parāda apkalpošanas maksājumu attiecība pret ienākumiem 2. ienākumu kvintilē - + @@ -3306,7 +3307,7 @@ Tautsaimniecības siltumnīcefekta gāzu emisiju samazināšana, izmantojot risinājumus klimata pārmaiņu mazināšanai un klimata tehnoloģiju atklājumus, un pieaugošas oglekļa dioksīda piesaistes nodrošināšana virzībā uz klimatnoturīgu ekonomikas attīstību, mērķtiecīgi sasniedzot augstu energoefektivitāti un transporta sistēmas dekarbonizāciju - + @@ -3340,7 +3341,7 @@ Klimata pārmaiņu ietekmju mazināšana, īstenojot pielāgošanās klimata pārmaiņām pasākumus un panākot materiāltehniskā un infrastruktūras nodrošinājuma uzlabojumus (katastrofu draudu, t. sk. plūdu un krasta erozijas, novēršanas un to pārvaldīšanas pasākumu īstenošanai), kā arī tautsaimniecības nozaru pārvaldībā, un ilgtspējīgā nokrišņu notekūdeņu apsaimniekošanā, ņemot vērā jaunākos zinātniskos datus un prognozes par klimatnoturīguma sasniegšanu un stiprināšanu - + @@ -3366,7 +3367,7 @@ Gaisa kvalitātes uzlabošana slāpekļa oksīdu (NOx), amonjaka un daļiņu PM₂,₅ piesārņojuma samazināšanai blīvi apdzīvotās vietās un valstī kopumā, mērķtiecīgi sasniedzot augstu energoefektivitāti, oglekļa mazietilpīgu ražošanu un uzlabojot transporta sistēmas - + @@ -3387,7 +3388,7 @@ Augstas un labas kvalitātes virszemes un pazemes ūdensobjektu īpatsvara palielinājuma panākšana, kā arī iekšzemes ūdensobjektu un jūras vides stāvokļa uzlabošana un pazemes ūdens resursu aizsardzība, samazinot antropogēno slodzi, t. sk. notekūdeņu kaitīgo ietekmi uz dabas resursiem un vidi, nodrošinot nepieciešamās infrastruktūras izveidi un veicinot notekūdeņu dūņu apstrādi - + @@ -3411,7 +3412,7 @@ Vietējo resursu, tāpat bioresursu, efektīvāka izmantošana (ekodizaina principu piemērošana un aprites ekonomikas ieviešana dažādos tautsaimniecības sektoros), jo īpaši sasniedzot augstāku standartu un inovāciju izmantošanu pārtikas apritē un dzīvnieku veselībā saskaņā ar “vienas veselības” principu, kā arī veicinot bezatkritumu ražošanas tehnoloģiju un inovāciju ieviešanu tautsaimniecībā - + @@ -3454,7 +3455,7 @@ Atkritumu rašanās un apglabājamo atkritumu samazināšana un atkritumu pārstrādes un reģenerācijas īpatsvara palielināšana, īpaši akcentējot notekūdeņu dūņu apstrādi un bioloģiski noārdāmo atkritumu pārstrādes un to reģenerācijas īpatsvara un jaudas palielinājumu - + @@ -3478,7 +3479,7 @@ Vēsturiski piesārņoto vietu sanācijas un revitalizācijas pasākumu īstenošana uzlabotas vides kvalitātes (augsnei, gruntij, pazemes un virszemes ūdeņiem) sasniegšanai - + @@ -3847,7 +3848,7 @@ - Savienības savienojamības atbilstoša platjoslas sakaru tīkla attīstot “vidējās “pēdējās jūdzes” sakaru tīklu un izveidojot kartēšanu + Eiropas Savienības savienojamības mērķiem atbilstoša platjoslas elektronisko sakaru tīkla izveidošana, attīstot “vidējās jūdzes” un “pēdējās jūdzes” elektronisko sakaru tīklu infrastruktūru un izveidojot platjoslas kartēšanu @@ -3862,7 +3863,7 @@ - tehnoloģiju un resursu efektīvas, un atvērtas ieviešana, nodrošinātu pakalpojumus, ievērojot digitāls”, proaktīvas sniegšanas un principu, t. sk. kā arī veiktu valsts un pašvaldību IKT un atbalsta procesu un centralizāciju + Mūsdienu tehnoloģiju un racionālas, resursu efektīvas, lietotājorientētas un atvērtas pārvaldības ieviešana, lai kvalitatīvi nodrošinātu publiskos pakalpojumus, ievērojot “primāri digitāls”, proaktīvas pakalpojumu sniegšanas un vienreizes principu, t. sk. pārrobežu, kā arī veiktu valsts pārvaldes un pašvaldību IKT infrastruktūras un atbalsta procesu optimizāciju un centralizāciju @@ -3888,7 +3889,7 @@ - digitālās pieejamības un palielināšana valsts infrastruktūrā, kā risinājumu veicināšana, iedzīvotāju digitālās elektroniskās un drošas parakstīšanās nodrošinot vides kvalitatīvai sniegšanai + Fiziskās un digitālās vides pieejamības un piekļūstamības palielināšana valsts un pašvaldību infrastruktūrā, kā arī digitālo risinājumu izmantošanas veicināšana, paaugstinot iedzīvotāju digitālās prasmes, pilnveidojot elektroniskās identifikācijas un drošas elektroniskās parakstīšanās sistēmu un nodrošinot vides pieejamību kvalitatīvai pakalpojumu sniegšanai @@ -3912,7 +3913,7 @@ - drošības un palielināšana un pilnīgu enerģijas tirgu turpinot iesaisti valstu elektrotīklu un gāzes vienotā vienlaikus atbalstot enerģētikas mikroprojektus, mājsaimniecības ražošanā no avotiem pašu un energotaupīgu ēku un atjaunošanā + Enerģētiskās drošības un neatkarības palielināšana un virzība uz pilnīgu enerģijas tirgu integrāciju, turpinot iesaisti Baltijas valstu elektrotīklu sinhronizācijā un gāzes vienotā tirgus izveidē, vienlaikus atbalstot civilās enerģētikas mikroprojektus, lai iesaistītu mājsaimniecības enerģijas ražošanā no atjaunojamiem avotiem pašu patēriņam un energotaupīgu ēku būvniecībā un atjaunošanā @@ -6067,7 +6068,7 @@ Nepietiekama publiskās pārvaldes efektivitāte un nepietiekami ātra reaģēšana uz biznesa vides vajadzībām. Ņemot vērā ārējās vides straujās izmaiņas, valsts pārvaldes spēja operatīvi reaģēt, nodrošinot atbilstošos uzņēmējdarbības vides nosacījumus, ir apgrūtināta. Pēdējos gados ir vērojama regulējošā ietvara un administratīvo šķēršļu negatīvās ietekmes uz uzņēmējiem palielināšanās, par ko liecina Latvijas rādītāju pazemināšanās starptautiskajos konkurētspējas un citos ekonomiskajos reitingos un Latvijas uzņēmēju aptauju rezultāti. Iekšējā un ārējā administratīvā sloga mazināšanas darbību efektivitāti traucē sadrumstalotība, izstrādāto metožu praktiskās pielietojamības un kapacitātes trūkums. Institucionālā vide jau ilgstoši tiek minēta kā Latvijas konkurētspējas vājā puse, tieši tāpēc izaugsmei, ko balsta produktivitāte, ir nepieciešamas reformas un investīcijas tieši šajā jomā. Kā būtiskākas institucionālās vides nepilnības, kas ierobežo konkurētspēju, Latvijas uzņēmēji atzīmē neefektīvu valdības birokrātiju, nestabilu (tuvredzīgu) politikas veidošanas praksi, neefektīvu tiesu sistēmu. (Datu avots: EM) - Neprogno zējama nodokļu politika. Straujas un nepārdomātas izmaiņas nodokļu politikā valsts budžeta apstiprināšanas procesā kavē valsts ekonomisko attīstību. Nodokļu politikas un uzņēmējdarbības vides stabilitātes trūkuma apstākļos uzņēmumiem ir sarežģīti ilgtermiņā plānot darbību, budžetu un investīcijas. Nestabila nodokļu politika ir viens no iemesliem, kādēļ samazinās piesaistīto ārvalstu tiešo investīciju apmērs. (Datu avots: FM) + Neprognozējama nodokļu politika. Straujas un nepārdomātas izmaiņas nodokļu politikā valsts budžeta apstiprināšanas procesā kavē valsts ekonomisko attīstību. Nodokļu politikas un uzņēmējdarbības vides stabilitātes trūkuma apstākļos uzņēmumiem ir sarežģīti ilgtermiņā plānot darbību, budžetu un investīcijas. Nestabila nodokļu politika ir viens no iemesliem, kādēļ samazinās piesaistīto ārvalstu tiešo investīciju apmērs. (Datu avots: FM) Nepietiekams finanšu sektora dziļums. Finanšu sektorā kā finansējuma avots galvenokārt dominē kredītiestādes, savukārt alternatīvi finansējuma avoti ir nepietiekamā apjomā, uzņēmumiem nav pieejama pietiekama finanšu instrumentu daudzveidība. Kapitāla tirgus attīstības līmenis ir būtiski zemāks par optimālo, tādējādi netiek nodrošināta iekšzemē uzkrātā kapitāla (piemēram, noguldījumu un pensiju fondu līdzekļu) tālāka ieguldīšana tautsaimniecībā, kā arī nepietiekami aktīvais kapitāla tirgus nav pievilcīgs ārvalstu investoriem. (Datu avots: FM) @@ -6292,7 +6293,7 @@ - Fiziskajām aktivitātēm un sportošanai atbilstošas vides un infrastruktūras trūkums, kas, piemēram, var kavēt sportisko rezultātu sasniegšanu (augstu sasniegumu sports). Pēc Izglītības un zinātnes ministrijas sniegtās informācijas (2019), jauno sportistu sagatavošanu Latvijā īsteno 81 profesionālās ievirzes sporta izglītības iestāde, kur 1518 treneru vadībā regulāri trenējas 38 990 bērni un jaunieši 38 sporta veidos. Latvijā ir 3185 sporta objekti un 1229 sporta bāzes, kas pašlaik ir reģistrētas sporta bāzu reģistrā. Savukārt attiecībā uz augstu sasniegumu sportu Latvijas Oli mpiskajā vienībā ir 168 sportisti – 55 sportisti ziemas sporta veidos un 113 sportisti vasaras sporta veidos. Salīdzinājumā ar 2017./2018. m. g. valsts finansēto audzēkņu skaits palielinājies par 1750, savukārt salīdzinājumā ar 2016./2017. m. g. palielinājies par 2755, bet saistībā ar audzēkņu skaita palielinājumu nav piešķirts papildu finansējums. + Fiziskajām aktivitātēm un sportošanai atbilstošas vides un infrastruktūras trūkums, kas, piemēram, var kavēt sportisko rezultātu sasniegšanu (augstu sasniegumu sports). Pēc Izglītības un zinātnes ministrijas sniegtās informācijas (2019), jauno sportistu sagatavošanu Latvijā īsteno 81 profesionālās ievirzes sporta izglītības iestāde, kur 1518 treneru vadībā regulāri trenējas 38 990 bērni un jaunieši 38 sporta veidos. Latvijā ir 3185 sporta objekti un 1229 sporta bāzes, kas pašlaik ir reģistrētas sporta bāzu reģistrā. Savukārt attiecībā uz augstu sasniegumu sportu Latvijas Olimpiskajā vienībā ir 168 sportisti – 55 sportisti ziemas sporta veidos un 113 sportisti vasaras sporta veidos. Salīdzinājumā ar 2017./2018. m. g. valsts finansēto audzēkņu skaits palielinājies par 1750, savukārt salīdzinājumā ar 2016./2017. m. g. palielinājies par 2755, bet saistībā ar audzēkņu skaita palielinājumu nav piešķirts papildu finansējums. @@ -6401,7 +6402,7 @@ Bezatkritumu dzīvesveids paredz visu resursu saglabāšanu, atbildīgu ražošanu, patērējot, atkārtoti izmantojot un reģenerējot produktus, iesaiņojumus un materiālus bez sadedzināšanas un bez izplūdēm zemē, ūdenī vai gaisā, kas apdraud vidi vai cilvēku veselību. Atbilstoši 2019. gada SEG inventarizācijai iesniegta Konvencijas un Kioto protokola ietvaros. Izejas dati: - IKP vērtība (salīdzināmajās cenās pret 2010. gadu) atbilstoši Eiropas Komisijā 2019. gadā iesniegtajiem ziņojumam par politikām, pasākumiem un SEG prognozēm. - Kopējās SEG emisijas (neieskaitot ZIZIMM sektoru) atbilstoši mērķim, kas noteikts Latvijas oglekļa mazietilpīgas attīstības stratēģijas 2050. gadam projektā (2030. gada mērķis – 65 % SEG samazinājums salīdzinot ar 1990. gadu). - Izejas dati: - IKP vērtība (salīdzināmajās cenās pret 2010. gadu) atbilstoši Eiropas Komisijā 2019. gadā iesniegtajam ziņojumam par politikām, pasākumiem un SEG prognozēm. Kopējās SEG emisijas (neieskaitot ZIZIMM sektoru) atbilstoši mērķim, kas noteikts Latvijas oglekļa mazietilpīgas attīstības stratēģijas 2050. gadam projektā (2030. gada mērķis – 65 % SEG samazinājums salīdzinot ar 1990. gadu). + Izejas dati: - IKP vērtība (salīdzināmajās cenās pret 2010. gadu) atbilstoši Eiropas Komisijā 2019. gadā iesniegtajam ziņojumam par politikām, pasākumiem un SEG prognozēm. - Kopējās SEG emisijas (neieskaitot ZIZIMM sektoru) atbilstoši mērķim, kas noteikts Latvijas oglekļa mazietilpīgas attīstības stratēģijas 2050. gadam projektā (2030. gada mērķis – 65 % SEG samazinājums salīdzinot ar 1990. gadu). Aprēķina kā kopējo emisiju un kopējās piesaistes summu visās regulas (ES) 2018/841 2. pantā minētajās zemes uzskaites kategorijās kopā atbilstoši regulā (ES) 2018/841 noteiktajiem uzskaites noteikumiem. Aprēķina kā kopējo emisiju un kopējās piesaistes summu visās regulas (ES) 2018/841 2. pantā minētajās zemes uzskaites kategorijās kopā atbilstoši regulā (ES) 2018/841 noteiktajiem uzskaites noteikumiem. Zemes sektors – zemes izmantošanas, zemes izmantošanas maiņas un mežsaimniecības sektors (ZIZIMM). diff --git a/schemas/strategija-0.1.xsd b/schemas/strategija-0.1.xsd index ea664cb..f7b053f 100644 --- a/schemas/strategija-0.1.xsd +++ b/schemas/strategija-0.1.xsd @@ -304,6 +304,10 @@ + + Institūcija, kas par uzdevuma jomu atbild tagad, ja jomu pēc dokumenta pieņemšanas pārņēmusi cita institūcija (piemēram, vides aizsardzības politika no VARAM uz Klimata un enerģētikas ministriju). org paliek kā dokumentā. + + diff --git a/sources/nap2027/dalibnieki.yaml b/sources/nap2027/dalibnieki.yaml index ac521a9..631df3d 100644 --- a/sources/nap2027/dalibnieki.yaml +++ b/sources/nap2027/dalibnieki.yaml @@ -99,3 +99,11 @@ funding: "Šveices programma": CH "ES programmas jaunatnes jomā": ES-JAUNATNE "pilsoniskā iniciatīva": PILSONISKA + +# Uzdevumi, kuru jomu pēc NAP2027 pieņemšanas pārņēmusi cita institūcija. +# Datnē paliek dokumentā norādītā institūcija (org); currentOrg — institūcija, kas par jomu atbild tagad (PPPA vērtējums pēc +# funkciju nodošanas aktiem). Klimata politika — Klimata un enerģētikas ministrijā no 2023-01-01; vides aizsardzības politika +# (izņemot dabas aizsardzību) — no 2024-07-01. Dabas aizsardzība (bioloģiskā daudzveidība) paliek VARAM. +current: + - {label: VARAM, items: [281, 282], org: "20-0000", since: "2023-01-01", note: "Klimata politika (SEG emisijas, pielāgošanās klimata pārmaiņām)."} + - {label: VARAM, items: [283, 284, 285, 287, 288], org: "20-0000", since: "2024-07-01", note: "Vides aizsardzības politika: gaisa kvalitāte, ūdeņi, aprites ekonomika, atkritumi, piesārņotās vietas."} diff --git a/tools/build_nap2027.py b/tools/build_nap2027.py index c4b0b79..c4d8e49 100644 --- a/tools/build_nap2027.py +++ b/tools/build_nap2027.py @@ -47,7 +47,7 @@ def main(src, out): d = json.load(open(src, encoding="utf-8")) m = yaml.safe_load(open(os.path.join(ROOT, "sources/nap2027/dalibnieki.yaml"), encoding="utf-8")) actors = {x["label"]: x for x in m["actors"]} - used_actors, used_funding, unresolved = {}, {}, [] + used_actors, used_funding, unresolved, used_current = {}, {}, [], set() # ---------------------------------------------------------------- actors def actor_list(printed): @@ -68,11 +68,19 @@ def main(src, out): out_.append({"label": q, "org": actors[q].get("org")}) return out_ - def actors_xml(tag, printed): + cur = {(n, c["label"]): c for c in m.get("current", []) for n in c["items"]} + + def actors_xml(tag, printed, n=None): lst = actor_list(printed) + for x in lst: + c = cur.get((n, x["label"])) + if c: + x["currentOrg"], x["currentSince"] = c["org"], c["since"] + used_current.add((n, x["label"])) if not lst: return "" - inner = "".join(f"" for x in lst) + inner = "".join(f"" for x in lst) return f"<{tag}{a('printed', printed)}>{inner}" # ---------------------------------------------------------------- funding @@ -156,8 +164,8 @@ def main(src, out): + el("BaseValue", x.get("baseValue")) + el("Target", x.get("target2024"), year="2024") + el("Target", x.get("target2027"), year="2027") + el("DataSource", x.get("source")) + "") elif x["kind"] == "task": - body = ("" + el("Text", x["text"]) + actors_xml("Responsible", x.get("responsible")) - + actors_xml("CoResponsible", x.get("coResponsible")) + funding_xml(x.get("funding")) + body = ("" + el("Text", x["text"]) + actors_xml("Responsible", x.get("responsible"), x["number"]) + + actors_xml("CoResponsible", x.get("coResponsible"), x["number"]) + funding_xml(x.get("funding")) + task_indicators(x) + "") else: title = x.get("title") if x["kind"] == "strategicGoal" else None @@ -235,6 +243,7 @@ def main(src, out): + el("Change", f"Pirmā versija: {len(d['items'])} numurētie punkti [1]–[475], {len(d['evidence'])} pamatojuma punkti, " f"{len(d['footnotes'])} zemsvītras piezīmes, {len(d['abbreviations'])} saīsinājumi.") + el("Change", "Atbildīgās un līdzatbildīgās institūcijas sasaistītas ar VPK ID; drukātais apzīmējums saglabāts.") + + el("Change", "Uzdevumiem, kuru jomu pārņēmusi Klimata un enerģētikas ministrija (klimata politika no 2023-01-01, vides aizsardzības politika no 2024-07-01), pie VARAM norādīta pašreizējā institūcija (currentOrg).") + "") xml = ('\n' @@ -248,6 +257,10 @@ def main(src, out): with open(out, "wb") as f: f.write(etree.tostring(tree, xml_declaration=True, encoding="UTF-8", pretty_print=True)) print("wrote", out, "actors", len(used_actors), "funding", len(used_funding), "indicator links", match_stats) + want = {(n, c["label"]) for c in m.get("current", []) for n in c["items"]} + if want - used_current: + unresolved += [f"current: {k}" for k in sorted(want - used_current)] + print("current institution set for", len(used_current), "task actors") if unresolved: print("UNRESOLVED", sorted(set(unresolved))) sys.exit(1) diff --git a/tools/parse_nap.py b/tools/parse_nap.py index 0ead0d7..94c1e47 100644 --- a/tools/parse_nap.py +++ b/tools/parse_nap.py @@ -37,9 +37,9 @@ def load_vocab(pdf_path): def _better(whole, *parts): - """Join when the whole word is attested more often than any of its fragments.""" + """Join when the whole word is attested more often than any of its fragments, or once while a fragment never is.""" n = VOCAB.get(whole, 0) + VOCAB.get(whole.lower(), 0) - return n >= 2 and any(VOCAB.get(p, 0) < n for p in parts) + return (n >= 2 and any(VOCAB.get(p, 0) < n for p in parts)) or (n >= 1 and any(VOCAB.get(p, 0) == 0 for p in parts)) def repair(s): @@ -50,7 +50,7 @@ def repair(s): if out: a, core = out[-1], t.rstrip(".,;:)”") ca = a.lstrip("“(") - if "/" in a or "http" in a or "www." in a: + if "http" in a or "www." in a or ("/" in a and re.search(r"[_.%=?&]|/.*/|-$", a)): out.append(t) continue # three fragments "fundamentāl a s" @@ -101,7 +101,7 @@ def page_lines(pdf): # footnotes: small text at the bottom of the page marks = [w["top"] for w in ws if w["size"] < 6.5 and w["text"].isdigit() and w["x0"] < 90 and w["top"] > 550] fz = min(marks) - 1.5 if marks else 9999 - infoot = lambda w: w["size"] < 9.5 and w["top"] >= fz + infoot = lambda w: w["size"] < 10.5 and w["top"] >= fz foot = [w for w in ws if infoot(w)] body = [w for w in ws if not infoot(w) and w["size"] >= 7.5] smalls = [w for w in ws if not infoot(w) and w["size"] < 7.5] @@ -242,6 +242,7 @@ def assign(words, centers, names, bounds=None): for w in words: cx = (w["x0"] + w["x1"]) / 2 i = sum(1 for b in bounds if cx > b) + i = max(i, 1) # the row marker is not among the words: nothing belongs to the "Nr." column cells[names[i]].append(w) return cells diff --git a/tools/validate.py b/tools/validate.py index 28daaa7..1198cba 100644 --- a/tools/validate.py +++ b/tools/validate.py @@ -27,7 +27,8 @@ REG_URL = "https://processgit.org/Valsts-Pirmkods/Valdibas-Deklaracija-as-Code/r def main(): reg_src = sys.argv[sys.argv.index("--registry") + 1] if "--registry" in sys.argv else REG_URL - reg = etree.parse(reg_src if os.path.exists(reg_src) else urllib.request.urlopen(reg_src)) + reg = etree.parse(reg_src if os.path.exists(reg_src) else + urllib.request.urlopen(urllib.request.Request(reg_src, headers={"User-Agent": "strategy-as-code-validate/0.1"}))) ids = {o.get("id") for o in reg.getroot() if etree.QName(o).localname == "Organization"} xsd = etree.XMLSchema(etree.parse(os.path.join(ROOT, "schemas/strategija-0.1.xsd"))) cat = yaml.safe_load(open(os.path.join(ROOT, "planosanas-dokumenti.yaml"), encoding="utf-8")) @@ -47,7 +48,7 @@ def main(): sha = hashlib.sha256(open(src, "rb").read()).hexdigest() if sha != root.findtext("s:Metadata/s:Source/s:SHA256", namespaces=NS): errors.append(f"{d['id']}: avota sha256 nesakrīt") - used = {e.get("org") for e in root.iter() if e.get("org")} + used = {e.get(k) for e in root.iter() for k in ("org", "currentOrg") if e.get(k)} missing = sorted(used - ids) if missing: errors.append(f"{d['id']}: VPK ID nav reģistrā: {', '.join(missing)}") diff --git a/tools/verify_nap2027.py b/tools/verify_nap2027.py index 2e770fb..a4e752d 100644 --- a/tools/verify_nap2027.py +++ b/tools/verify_nap2027.py @@ -21,6 +21,7 @@ from lxml import etree NS = {"s": "urn:pppa:vpk:strategija:0.1"} HEADER = "latvijasnacionālaisattīstībasplānsgadam" +BOILER = set() SUBS = str.maketrans("₀₁₂₃₄₅₆₇₈₉", "0123456789") @@ -55,6 +56,9 @@ def main(xml_path, pdf_path, out): lay = subprocess.run(["pdftotext", "-layout", pdf_path, "-"], capture_output=True, text=True, check=True).stdout flat = letters(raw).replace(HEADER, "") doc = etree.parse(xml_path) + # words that may stand between table rows in the PDF and belong elsewhere in the file: footnotes, sub-section titles + BOILER.update(words(" ".join(x.text for x in doc.findall(".//s:Footnote", NS)))) + BOILER.update(words(" ".join(x.text for x in doc.findall(".//s:Section/s:Title", NS)))) items = doc.findall(".//s:Item", NS) res = {"file": xml_path, "pdf_sha256": hashlib.sha256(open(pdf_path, "rb").read()).hexdigest(), "checks": {}} @@ -67,14 +71,27 @@ def main(xml_path, pdf_path, out): # layout blocks between consecutive markers pos = {int(m.group(1)): m.end() for m in re.finditer(r"\[(\d{1,3})\]", lay)} + start = {int(m.group(1)): m.start() for m in re.finditer(r"\[(\d{1,3})\]", lay)} order = sorted(pos) def block(n): k = order.index(n) - end = pos[order[k + 1]] if k + 1 < len(order) else len(lay) + end = start[order[k + 1]] if k + 1 < len(order) else len(lay) return lay[pos[n]:end] - text_bad, text_split, row_bad, row_words, text_n, row_n = [], [], [], 0, 0, 0 + text_bad, text_split, row_bad, row_extra, row_words, text_n, row_n = [], [], [], [], 0, 0, 0 + + def block_rows(n): + """The row's lines only: stop at a blank line followed by body text, drop page header/footer lines.""" + out = [] + for ln in block(n).split("\n"): + st = ln.strip() + if not st or re.fullmatch(r"\d{1,3}", st) or st.startswith("Latvijas Nacionālais attīstības plāns"): + continue + if re.match(r"^(Rīcības virziena|RĪCĪBAS|PRIORITĀTES|Prioritāte|NAP2027|Nr\.|\*|\d{1,2} [A-ZĀČĒĢĪĶĻŅŠŪŽa-z])", st) or len(ln) - len(ln.lstrip()) == 0 and len(st) > 60: + break + out.append(ln) + return "\n".join(out) for it in items: n, kind = int(it.get("n")), it.get("kind") if kind in ("indicator", "task"): @@ -97,6 +114,19 @@ def main(xml_path, pdf_path, out): missing.append(w) if missing: row_bad.append({"n": n, "missing_words": missing[:10]}) + # reverse: every word printed in the row's part of the PDF is in the file (nothing dropped) + xw = set(words(" ".join(vals))) + xjoin = " ".join(sorted(xw)) + extra = [] + for w in words(block_rows(n)): + w2 = re.sub(r"(?<=[a-zāčēģīķļņšūž])\d{1,2}$", "", w) # footnote number printed after a word + if w in xw or w2 in xw or w in BOILER or w2 in BOILER or (w.isdigit() or len(w) >= 2) and w in xjoin: + continue + if w.isdigit() and len(w) > 2 and (w[:-1] in xw or w[:-2] in xw): # number followed by a footnote number + continue + extra.append(w) + if extra: + row_extra.append({"n": n, "words_not_in_file": extra[:12]}) else: text_n += 1 ks = [runs(letters(x.text), flat) for x in it.findall("s:Text", NS) + it.findall("s:Area", NS)] @@ -107,7 +137,8 @@ def main(xml_path, pdf_path, out): text_split.append(n) res["checks"]["text_items"] = {"checked": text_n, "not_found_verbatim": text_bad, "found_in_2_to_4_pieces": text_split} - res["checks"]["table_rows"] = {"checked": row_n, "words": row_words, "rows_with_missing_words": row_bad} + res["checks"]["table_rows"] = {"checked": row_n, "words": row_words, "rows_with_missing_words": row_bad, + "rows_with_words_not_in_file": row_extra} ev = doc.findall(".//s:Evidence", NS) ev_bad = [e.get("id") for e in ev if (runs(letters((e.findtext("s:Problem", namespaces=NS) or "") + e.findtext("s:Text", namespaces=NS)), flat) or 99) > 4] @@ -122,7 +153,7 @@ def main(xml_path, pdf_path, out): "indicators": len(inds), "indicators_without_values": no_val} c = res["checks"] res["passed"] = not (c["numbering"]["missing"] or c["numbering"]["extra"] or c["numbering"]["duplicates"] or text_bad - or row_bad or ev_bad or no_resp) + or row_bad or row_extra or ev_bad or no_resp) with open(out, "w", encoding="utf-8") as f: json.dump(res, f, ensure_ascii=False, indent=1) print(json.dumps({k: {kk: (vv if not isinstance(vv, list) else (len(vv) if len(vv) > 12 else vv)) for kk, vv in v.items()} diff --git a/verification/lv-nap2027.verify.json b/verification/lv-nap2027.verify.json index e12eec2..64ecf00 100644 --- a/verification/lv-nap2027.verify.json +++ b/verification/lv-nap2027.verify.json @@ -25,8 +25,9 @@ }, "table_rows": { "checked": 255, - "words": 9684, - "rows_with_missing_words": [] + "words": 9742, + "rows_with_missing_words": [], + "rows_with_words_not_in_file": [] }, "evidence": { "checked": 154,