URL-Pattern verifiziert WP8 Sitzung 22: https://www.parlamentsdokumentation.brandenburg.de/starweb/LBB/ELVIS/parladoku/w8/plpr/{n}.pdf **Wichtig:** parladoku-PDF-URL liefert 403 ohne Cookie-Session. Erst GET auf portal/browse.tt.html?wp=8 zur Cookie-Akquise, dann mit gesetztem Cookie die PDF-URL aufrufen. Ingest-Cron implementiert diesen Flow per http.cookiejar.CookieJar in Python. Anchor-Pattern (NRW-aehnlich): - "Damit ist [Subj] (mehrheitlich|einstimmig)? (angenommen|abgelehnt|ueberwiesen)" - Drucksachen-Lookup: Drucksache 8/N rueckwaerts vom Anchor Vote-Style: Handzeichen-only (kein Fraktionen-Listing). Daher Vote-Listen leer; einstimmig=True setzt JA=alle WP8-Fraktionen (SPD, AfD, CDU, BSW, GRÜNE). Tests: 14 BB-Tests, Verifikation S22 → 26 Vote-Anchors extrahiert. Stand: 10 produktive Parser (NRW, BUND, BE, HH, TH, HE, SH, HB, SL, BB). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
84 lines
2.7 KiB
Python
84 lines
2.7 KiB
Python
"""Tests fuer app/protokoll_parsers/bb.py — BB Plenarprotokoll-Parser (#149).
|
|
|
|
Stichprobe-getestet gegen WP8 Sitzung 22 (Brandenburg).
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
from app.protokoll_parsers.bb import (
|
|
_normalize_text,
|
|
_resolve_drucksache_bb,
|
|
RESULT_ANCHOR_RE,
|
|
DS_RE_BB,
|
|
ALLE_FRAKTIONEN_BB,
|
|
)
|
|
|
|
|
|
class TestNormalizeText:
|
|
def test_collapses_whitespace(self):
|
|
assert _normalize_text("a b\n\tc") == "a b c"
|
|
|
|
def test_repairs_soft_hyphenation(self):
|
|
assert _normalize_text("zustim- mt") == "zustimmt"
|
|
|
|
|
|
class TestResultAnchorRegex:
|
|
def test_matches_mehrheitlich_abgelehnt(self):
|
|
m = RESULT_ANCHOR_RE.search("Damit ist der Antrag mehrheitlich abgelehnt.")
|
|
assert m
|
|
assert m.group("modus") == "mehrheitlich"
|
|
assert m.group("ergebnis") == "abgelehnt"
|
|
|
|
def test_matches_einstimmig_angenommen(self):
|
|
m = RESULT_ANCHOR_RE.search("Damit ist der Antrag einstimmig angenommen.")
|
|
assert m
|
|
assert m.group("modus") == "einstimmig"
|
|
|
|
def test_matches_entschliessungsantrag(self):
|
|
m = RESULT_ANCHOR_RE.search(
|
|
"Damit ist der Entschließungsantrag mehrheitlich abgelehnt."
|
|
)
|
|
assert m and m.group("subject") == "Entschließungsantrag"
|
|
|
|
def test_matches_beschlussempfehlung(self):
|
|
m = RESULT_ANCHOR_RE.search(
|
|
"Damit sind die Beschlussempfehlung mit Enthaltungen angenommen worden."
|
|
)
|
|
assert m and m.group("subject") == "Beschlussempfehlung"
|
|
|
|
def test_no_match_random(self):
|
|
m = RESULT_ANCHOR_RE.search("Der Antrag wurde abgelehnt.")
|
|
assert m is None
|
|
|
|
|
|
class TestDrucksacheRegex:
|
|
def test_matches_drucksache_8(self):
|
|
m = DS_RE_BB.search("Drucksache 8/2054")
|
|
assert m and m.group(1) == "2054"
|
|
|
|
def test_only_wp8_matches(self):
|
|
# Drucksache 7/123 sollte nicht matchen (anderer WP)
|
|
assert DS_RE_BB.search("Drucksache 7/123") is None
|
|
|
|
|
|
class TestResolveDrucksacheBb:
|
|
def test_finds_drucksache_before_anchor(self):
|
|
text = "Drucksache 8/2054 ... Damit ist der Antrag abgelehnt."
|
|
anchor = text.index("Damit")
|
|
assert _resolve_drucksache_bb(text, anchor) == "8/2054"
|
|
|
|
def test_picks_most_recent_drucksache(self):
|
|
text = "Drucksache 8/1000 ... Drucksache 8/2000 ... Damit ist abgelehnt."
|
|
anchor = text.index("Damit")
|
|
assert _resolve_drucksache_bb(text, anchor) == "8/2000"
|
|
|
|
def test_returns_none_when_no_ds(self):
|
|
assert _resolve_drucksache_bb("Damit ist abgelehnt.", 0) is None
|
|
|
|
|
|
class TestConstants:
|
|
def test_all_fraktionen_set(self):
|
|
# WP8-BB Konstellation: SPD-BSW Koalition + AfD/CDU/GRÜNE Opposition
|
|
assert set(ALLE_FRAKTIONEN_BB) == {"SPD", "AfD", "CDU", "BSW", "GRÜNE"}
|