#!/usr/bin/env python3 # ----------------------------------------------------------------------------- # Immo-Ka — Annuaire des bannières & courtiers immobiliers du Québec # bannieres.py : sert data/bannieres.json — les ~690 agences (bannières) du # registre OACIQ et leurs 17 357 courtiers (recensement complet, 17 régions). # Régénération du dataset : rescraper registre.oaciq.com (voir # data/oaciq_census.json pour la méthode) puis reconstruire le JSON. # ----------------------------------------------------------------------------- from __future__ import annotations import json import threading from pathlib import Path from fastapi import APIRouter, HTTPException ROOT = Path(__file__).resolve().parent.parent DATA = ROOT / "data" / "bannieres.json" router = APIRouter() _cache: dict = {"mtime": None, "doc": None, "index": None, "light": None} _lock = threading.Lock() def load() -> dict: """Charge (avec cache par mtime) l'annuaire canonique des bannières.""" try: mtime = DATA.stat().st_mtime except FileNotFoundError: return {"generated": None, "count": 0, "brokers_total": 0, "bannieres": [], "regions": []} with _lock: if _cache["doc"] is None or mtime != _cache["mtime"]: doc = json.loads(DATA.read_text(encoding="utf-8")) regs: dict[str, int] = {} for b in doc.get("bannieres", []): for r in b.get("regions", []): regs[r] = regs.get(r, 0) + 1 doc["regions"] = [{"region": r, "n": n} for r, n in sorted(regs.items(), key=lambda x: (-x[1], x[0]))] _cache["doc"], _cache["mtime"] = doc, mtime _cache["index"] = {b["id"]: b for b in doc.get("bannieres", [])} _cache["light"] = [{k: v for k, v in b.items() if k != "brokers"} for b in doc.get("bannieres", [])] return _cache["doc"] @router.get("/api/bannieres") def api_bannieres(region: str | None = None, q: str | None = None): """Liste des bannières (sans le détail des courtiers) — filtres région/texte.""" doc = load() items = _cache["light"] or [] if region: items = [b for b in items if region in b.get("regions", [])] if q: needle = q.strip().lower() items = [b for b in items if needle in b["name"].lower()] return {"generated": doc.get("generated"), "total": doc.get("count", 0), "brokers_total": doc.get("brokers_total", 0), "count": len(items), "regions": doc.get("regions", []), "bannieres": items} @router.get("/api/bannieres/{banniere_id}") def api_banniere(banniere_id: str): """Une bannière avec la liste complète de ses courtiers.""" load() b = (_cache["index"] or {}).get(banniere_id) if b is None: raise HTTPException(status_code=404, detail="bannière inconnue") return b