2026-04-25 20:55:16 +02:00
|
|
|
"""Erkennung fehlender Wahlprogramme (#128).
|
|
|
|
|
|
|
|
|
|
Prüft für ein gegebenes Bundesland, welche der im Landtag vertretenen
|
refactor(programme): WAHLPROGRAMME → programme.PROGRAMME konsolidiert (#222)
Schließt #222. Entfernt die Doppelung zwischen ``wahlprogramme.WAHLPROGRAMME``
und ``programme.PROGRAMME``. Single source of truth ist jetzt
``programme.PROGRAMME`` als Literal mit allen 287 Programmen
(Wahlprogramme + Bundes- + Landes-Grundsatzprogramme, historisch + aktuell).
Schema schmaler — Felder ohne Konsumenten entfallen:
- ``regierungsbildung`` / ``regierungsende`` → gehören zu
``legislaturen.REGIERUNGEN``. Verbindung Programm→Regierung läuft jetzt
über ``legislaturen.regierung_zum_zeitpunkt(bl, datum)``.
- ``partei`` (Langform "CDU NRW") → ableitbar aus partei + bundesland.
- ``jahr`` → ableitbar aus ``gueltig_ab[:4]``.
- ``beschluss`` / ``wahl`` / ``hinweis`` → keine App-Konsumenten.
Felder im neuen Schema: id, typ, partei, bundesland, wp, gueltig_ab,
gueltig_bis, name, titel (Slogan, optional), pdf, seiten.
Daten-Migration einmalig via ``tools/build_programme_literal.py``:
- Basis: bisherige embeddings.PROGRAMME (alle 287 IDs + gueltig_ab/bis)
- titel aus WAHLPROGRAMME für die ~80 aktuellen Wahlprogramme +
Land-Grundsatzprogramm-Slogans (ehem. _ARCHIVED_SKELETONS)
- seiten via ``fitz.open(p).page_count`` für alle 287 PDFs
Aufrufer migriert:
- app/main.py:4055 — ``aktuelles_wahlprogramm(bl, partei).pdf``
- app/wahlprogramm_check.py — ``parteien_mit_wahlprogramm(bl)``
- app/redline_utils.py — Reverse-Lookup über ``all_programme()``
- app/wahlprogramm_fetch.py (3 Stellen) — ``aktuelles_wahlprogramm()``
- tests/test_redline_parser.py — Programm-Lookup statt WAHLPROGRAMME
``wahlprogramme.py`` schrumpft auf den Such-Code: Keyword-Fallback +
PDF-Text-Loader + ein dünner ``get_wahlprogramm``-Compat-Adapter zu
``programme.aktuelles_wahlprogramm``.
Drei Helper gelöscht (keine App-Konsumenten):
``regierungsbildung_for``, ``regierungsende_for``, ``regierung_aktuell``.
Wer das Datum der Regierungsbildung will, fragt
``legislaturen.aktuelle_regierung(bl).get('von')``.
Test-Suite: 1217 grün (vorher 1244, Differenz 27 = entfernte
regierungs-Helper-Tests + obsolete WAHLPROGRAMME-Strukturtests).
2026-05-09 00:37:35 +02:00
|
|
|
Fraktionen in der ``programme``-Registry nicht hinterlegt sind. Wird
|
|
|
|
|
nach dem LLM-Call in ``analyze_antrag()`` aufgerufen, damit das
|
2026-04-25 20:55:16 +02:00
|
|
|
Assessment-Ergebnis die Lücken explizit ausweist.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
from .bundeslaender import BUNDESLAENDER
|
refactor(programme): WAHLPROGRAMME → programme.PROGRAMME konsolidiert (#222)
Schließt #222. Entfernt die Doppelung zwischen ``wahlprogramme.WAHLPROGRAMME``
und ``programme.PROGRAMME``. Single source of truth ist jetzt
``programme.PROGRAMME`` als Literal mit allen 287 Programmen
(Wahlprogramme + Bundes- + Landes-Grundsatzprogramme, historisch + aktuell).
Schema schmaler — Felder ohne Konsumenten entfallen:
- ``regierungsbildung`` / ``regierungsende`` → gehören zu
``legislaturen.REGIERUNGEN``. Verbindung Programm→Regierung läuft jetzt
über ``legislaturen.regierung_zum_zeitpunkt(bl, datum)``.
- ``partei`` (Langform "CDU NRW") → ableitbar aus partei + bundesland.
- ``jahr`` → ableitbar aus ``gueltig_ab[:4]``.
- ``beschluss`` / ``wahl`` / ``hinweis`` → keine App-Konsumenten.
Felder im neuen Schema: id, typ, partei, bundesland, wp, gueltig_ab,
gueltig_bis, name, titel (Slogan, optional), pdf, seiten.
Daten-Migration einmalig via ``tools/build_programme_literal.py``:
- Basis: bisherige embeddings.PROGRAMME (alle 287 IDs + gueltig_ab/bis)
- titel aus WAHLPROGRAMME für die ~80 aktuellen Wahlprogramme +
Land-Grundsatzprogramm-Slogans (ehem. _ARCHIVED_SKELETONS)
- seiten via ``fitz.open(p).page_count`` für alle 287 PDFs
Aufrufer migriert:
- app/main.py:4055 — ``aktuelles_wahlprogramm(bl, partei).pdf``
- app/wahlprogramm_check.py — ``parteien_mit_wahlprogramm(bl)``
- app/redline_utils.py — Reverse-Lookup über ``all_programme()``
- app/wahlprogramm_fetch.py (3 Stellen) — ``aktuelles_wahlprogramm()``
- tests/test_redline_parser.py — Programm-Lookup statt WAHLPROGRAMME
``wahlprogramme.py`` schrumpft auf den Such-Code: Keyword-Fallback +
PDF-Text-Loader + ein dünner ``get_wahlprogramm``-Compat-Adapter zu
``programme.aktuelles_wahlprogramm``.
Drei Helper gelöscht (keine App-Konsumenten):
``regierungsbildung_for``, ``regierungsende_for``, ``regierung_aktuell``.
Wer das Datum der Regierungsbildung will, fragt
``legislaturen.aktuelle_regierung(bl).get('von')``.
Test-Suite: 1217 grün (vorher 1244, Differenz 27 = entfernte
regierungs-Helper-Tests + obsolete WAHLPROGRAMME-Strukturtests).
2026-05-09 00:37:35 +02:00
|
|
|
from .programme import parteien_mit_wahlprogramm
|
2026-04-25 20:55:16 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def check_missing_programmes(bundesland: str, fraktionen: list[str]) -> list[str]:
|
|
|
|
|
"""Gibt eine Liste der Fraktions-Namen zurück, für die kein Wahlprogramm
|
|
|
|
|
im gegebenen Bundesland hinterlegt ist.
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
bundesland: Bundesland-Code (z.B. "NRW", "BY").
|
|
|
|
|
fraktionen: Liste der Fraktionen, die geprüft werden sollen
|
|
|
|
|
(typischerweise aus BUNDESLAENDER[bl].landtagsfraktionen).
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
Geordnete Liste der Fraktions-Namen ohne hinterlegtes Wahlprogramm.
|
|
|
|
|
Leere Liste, wenn für alle Fraktionen Programme vorliegen oder
|
|
|
|
|
fraktionen leer ist.
|
|
|
|
|
|
|
|
|
|
Raises:
|
|
|
|
|
ValueError: Wenn das Bundesland nicht in BUNDESLAENDER bekannt ist.
|
|
|
|
|
"""
|
|
|
|
|
if bundesland not in BUNDESLAENDER:
|
|
|
|
|
raise ValueError(f"Unbekanntes Bundesland: {bundesland!r}")
|
|
|
|
|
|
|
|
|
|
if not fraktionen:
|
|
|
|
|
return []
|
|
|
|
|
|
refactor(programme): WAHLPROGRAMME → programme.PROGRAMME konsolidiert (#222)
Schließt #222. Entfernt die Doppelung zwischen ``wahlprogramme.WAHLPROGRAMME``
und ``programme.PROGRAMME``. Single source of truth ist jetzt
``programme.PROGRAMME`` als Literal mit allen 287 Programmen
(Wahlprogramme + Bundes- + Landes-Grundsatzprogramme, historisch + aktuell).
Schema schmaler — Felder ohne Konsumenten entfallen:
- ``regierungsbildung`` / ``regierungsende`` → gehören zu
``legislaturen.REGIERUNGEN``. Verbindung Programm→Regierung läuft jetzt
über ``legislaturen.regierung_zum_zeitpunkt(bl, datum)``.
- ``partei`` (Langform "CDU NRW") → ableitbar aus partei + bundesland.
- ``jahr`` → ableitbar aus ``gueltig_ab[:4]``.
- ``beschluss`` / ``wahl`` / ``hinweis`` → keine App-Konsumenten.
Felder im neuen Schema: id, typ, partei, bundesland, wp, gueltig_ab,
gueltig_bis, name, titel (Slogan, optional), pdf, seiten.
Daten-Migration einmalig via ``tools/build_programme_literal.py``:
- Basis: bisherige embeddings.PROGRAMME (alle 287 IDs + gueltig_ab/bis)
- titel aus WAHLPROGRAMME für die ~80 aktuellen Wahlprogramme +
Land-Grundsatzprogramm-Slogans (ehem. _ARCHIVED_SKELETONS)
- seiten via ``fitz.open(p).page_count`` für alle 287 PDFs
Aufrufer migriert:
- app/main.py:4055 — ``aktuelles_wahlprogramm(bl, partei).pdf``
- app/wahlprogramm_check.py — ``parteien_mit_wahlprogramm(bl)``
- app/redline_utils.py — Reverse-Lookup über ``all_programme()``
- app/wahlprogramm_fetch.py (3 Stellen) — ``aktuelles_wahlprogramm()``
- tests/test_redline_parser.py — Programm-Lookup statt WAHLPROGRAMME
``wahlprogramme.py`` schrumpft auf den Such-Code: Keyword-Fallback +
PDF-Text-Loader + ein dünner ``get_wahlprogramm``-Compat-Adapter zu
``programme.aktuelles_wahlprogramm``.
Drei Helper gelöscht (keine App-Konsumenten):
``regierungsbildung_for``, ``regierungsende_for``, ``regierung_aktuell``.
Wer das Datum der Regierungsbildung will, fragt
``legislaturen.aktuelle_regierung(bl).get('von')``.
Test-Suite: 1217 grün (vorher 1244, Differenz 27 = entfernte
regierungs-Helper-Tests + obsolete WAHLPROGRAMME-Strukturtests).
2026-05-09 00:37:35 +02:00
|
|
|
indexed = set(parteien_mit_wahlprogramm(bundesland))
|
2026-04-25 20:55:16 +02:00
|
|
|
return [f for f in fraktionen if f not in indexed]
|