feat(analysis): fetch real MP metadata, fix anchor axis for party-level actors
- fetch_mp_metadata: use real OData URL with pagination (1200 records, 5 pages) uses Fractie.Afkorting not NaamNL for abbreviation matching skips Verwijderd=true records - upsert_mp_metadata: keep most recent membership (prefer active over ended, then higher Van date) so current party affiliations are not overwritten by historical - compute_anchor_axis: anchor directly on party-level SVD entities (GroenLinks-PvdA etc) before falling back to mp_metadata individual MP lookup - test_fetch_mp_metadata: fix mock for timeout kwarg + pagination + Afkorting field - Generated anchor axis HTML for 2025-Q2 through 2026-Q1 in outputs/
This commit is contained in:
@@ -28,44 +28,58 @@ class MockResponse:
|
||||
|
||||
|
||||
class MockSession:
|
||||
def __init__(self, response):
|
||||
self._response = response
|
||||
"""Session mock that returns a data page on first call and empty page on second."""
|
||||
|
||||
def get(self, url):
|
||||
return self._response
|
||||
def __init__(self, data_page):
|
||||
self._pages = [data_page, {"value": []}]
|
||||
self._call = 0
|
||||
|
||||
def get(self, url, **kwargs):
|
||||
resp = MockResponse(self._pages[min(self._call, len(self._pages) - 1)])
|
||||
self._call += 1
|
||||
return resp
|
||||
|
||||
|
||||
def test_fetch_mp_metadata_idempotent(tmp_path, monkeypatch):
|
||||
# Prepare canned OData response with two FractieZetelPersoon records
|
||||
# Prepare canned OData response with two FractieZetelPersoon records.
|
||||
# Use Afkorting (not NaamNL) because fetch_mp_metadata prefers Afkorting.
|
||||
data = {
|
||||
"value": [
|
||||
{
|
||||
"Verwijderd": False,
|
||||
"Persoon": {
|
||||
"Achternaam": "Yesilgöz-Zegerius",
|
||||
"Initialen": "D.",
|
||||
"Tussenvoegsel": None,
|
||||
"Id": "guid-1",
|
||||
},
|
||||
"FractieZetel": {"Fractie": {"NaamNL": "VVD"}},
|
||||
"FractieZetel": {
|
||||
"Fractie": {
|
||||
"Afkorting": "VVD",
|
||||
"NaamNL": "Volkspartij voor Vrijheid en Democratie",
|
||||
}
|
||||
},
|
||||
"Van": "2023-01-01",
|
||||
"TotEnMet": None,
|
||||
},
|
||||
{
|
||||
"Verwijderd": False,
|
||||
"Persoon": {
|
||||
"Achternaam": "Plas",
|
||||
"Initialen": "C.",
|
||||
"Tussenvoegsel": "van der",
|
||||
"Id": "guid-2",
|
||||
},
|
||||
"FractieZetel": {"Fractie": {"NaamNL": "BBB"}},
|
||||
"FractieZetel": {
|
||||
"Fractie": {"Afkorting": "BBB", "NaamNL": "BoerBurgerBeweging"}
|
||||
},
|
||||
"Van": "2023-06-01",
|
||||
"TotEnMet": "2024-01-01",
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
mock_resp = MockResponse(data)
|
||||
mock_session = MockSession(mock_resp)
|
||||
mock_session = MockSession(data)
|
||||
|
||||
# Patch requests.Session to return our mock session
|
||||
monkeypatch.setattr(requests, "Session", lambda: mock_session)
|
||||
@@ -98,6 +112,7 @@ def test_fetch_mp_metadata_idempotent(tmp_path, monkeypatch):
|
||||
assert rows[1][3] == None
|
||||
assert rows[1][4] == "guid-1"
|
||||
|
||||
# Run again to assert idempotence (no exception and same count processed)
|
||||
# Run again to assert idempotence: same records processed, DB unchanged
|
||||
monkeypatch.setattr(requests, "Session", lambda: MockSession(data))
|
||||
count2 = fetch_mp_metadata(db_path=db_path, odata_url="http://example/odata")
|
||||
assert count2 == 2
|
||||
|
||||
Reference in New Issue
Block a user