Files
simonandClaude Opus 5.5 583ccba31c Politrack: track Austrian politicians from public sources
Initial import of Politrack, a self-hosted service that tracks Austrian
politicians from federal to municipal level - roles, votes, money flows,
statements, meetings, social media and legal proceedings - with every claim
linked to its sources.

- backend: FastAPI + Postgres/pgvector; adapter framework (fetch -> parse ->
  load -> enrich) with robots.txt/TDM-aware fetching, a raw-response archive
  for reparsing, and a claim/evidence model with corroboration
- sources: Parliament, Wikidata, EU Parliament/Commission, Council of
  Ministers, Rechnungshof party reports and donations, procurement, RTR media
  transparency, political ad libraries, WKStA, news feeds, Wikipedia edits,
  Bluesky, Mastodon, public Telegram channels, YouTube and X (official API)
- web: Next.js frontend in German and English with typed API client
- mcp: MCP server for AI agents and RAG
- docs: architecture, data model, sources, legal notes, Unraid deployment and
  contributor guides; Docker Compose setup for Unraid

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 20:02:01 +01:00

41 lines
2.1 KiB
Python

"""Golden tests: replay captured responses through adapter.parse() and compare with the expected records.
Fixtures live in tests/fixtures/<adapter>/<case>.request.json (+ the body file it names) and are captured
with `politrack fixture <adapter> <url> <case> --kind ...`. The expected output <case>.expected.json is
(re)generated with `UPDATE_GOLDEN=1 pytest tests/test_golden.py` - review the diff before committing it.
"""
from __future__ import annotations
import json
import os
from pathlib import Path
import pytest
from politrack.core import registry
from politrack.core.records import to_jsonable
from politrack.core.runner import make_response, parse_offline
FIXTURES = Path(__file__).parent / "fixtures"
CASES = sorted(FIXTURES.glob("*/*.request.json"))
@pytest.mark.parametrize("request_file", CASES, ids=[f"{p.parent.name}:{p.name.removesuffix('.request.json')}"
for p in CASES])
def test_golden(request_file: Path) -> None:
spec = json.loads(request_file.read_text(encoding="utf-8"))
adapter = registry.get(request_file.parent.name)()
response = make_response(spec["url"], (request_file.parent / spec["body_file"]).read_bytes(), kind=spec["kind"],
meta=spec.get("meta"), content_type=spec.get("content_type", ""),
method=spec.get("method", "GET"), json_body=spec.get("json"), params=spec.get("params"))
actual = to_jsonable(parse_offline(adapter, response, spec.get("run_params")))
expected_file = request_file.with_name(request_file.name.replace(".request.json", ".expected.json"))
if os.environ.get("UPDATE_GOLDEN") or not expected_file.exists():
expected_file.write_text(json.dumps(actual, indent=1, ensure_ascii=False, sort_keys=True) + "\n",
encoding="utf-8")
if not os.environ.get("UPDATE_GOLDEN"):
pytest.skip(f"created {expected_file.name}; review it and re-run")
expected = json.loads(expected_file.read_text(encoding="utf-8"))
assert json.loads(json.dumps(actual, sort_keys=True)) == expected