SPB Git forge

spb/sorti-ka

Public

Toutes les sorties et tous les événements du Québec, un seul endroit — 7 connecteurs, fiches SSR, design Groupe KA.

58commits 1branches 0releases
13.7 MBsize
maindefault branch
17 days agolast push
HTML 82.9% Python 15.2% TypeScript 0.9% JavaScript 0.7%
6.4 KB · 174 lines python
Raw Blame History
1# -----------------------------------------------------------------------------2# Sorti-Ka — Agrégateur de sorties & événements (province de Québec)3# Auteur : Simon-Pierre Boucher — contact@spboucher.ai4# regions.py : les 17 régions administratives du Québec + correspondances5#              région touristique → région administrative et ville → région6#              (patron Lou-Ka : rattacher chaque fiche à sa région via l'adresse)7# -----------------------------------------------------------------------------8from __future__ import annotations910import re11import unicodedata1213# Les 17 régions administratives officielles (ordre des numéros 01-17).14REGIONS: list[str] = [15    "Bas-Saint-Laurent",16    "Saguenay–Lac-Saint-Jean",17    "Capitale-Nationale",18    "Mauricie",19    "Estrie",20    "Montréal",21    "Outaouais",22    "Abitibi-Témiscamingue",23    "Côte-Nord",24    "Nord-du-Québec",25    "Gaspésie–Îles-de-la-Madeleine",26    "Chaudière-Appalaches",27    "Laval",28    "Lanaudière",29    "Laurentides",30    "Montérégie",31    "Centre-du-Québec",32]333435def _k(s: str) -> str:36    """Clé de comparaison : minuscules, sans accents, tirets/points/apostrophes unifiés."""37    s = unicodedata.normalize("NFD", s or "")38    s = "".join(c for c in s if unicodedata.category(c) != "Mn")39    s = s.lower().replace("’", "'")40    return re.sub(r"[\s\-–—_'.]+", " ", s).strip()414243# Région touristique (SIT Québec / ATR, 22 régions) → région administrative.44TOURIST_TO_ADMIN: dict[str, str] = {45    _k("Abitibi-Témiscamingue"): "Abitibi-Témiscamingue",46    _k("Baie-James"): "Nord-du-Québec",47    _k("Eeyou Istchee Baie-James"): "Nord-du-Québec",48    _k("Nunavik"): "Nord-du-Québec",49    _k("Bas-Saint-Laurent"): "Bas-Saint-Laurent",50    _k("Cantons-de-l'Est"): "Estrie",51    _k("Centre-du-Québec"): "Centre-du-Québec",52    _k("Charlevoix"): "Capitale-Nationale",53    _k("Chaudière-Appalaches"): "Chaudière-Appalaches",54    _k("Côte-Nord"): "Côte-Nord",55    _k("Duplessis"): "Côte-Nord",56    _k("Manicouagan"): "Côte-Nord",57    _k("Gaspésie"): "Gaspésie–Îles-de-la-Madeleine",58    _k("Îles-de-la-Madeleine"): "Gaspésie–Îles-de-la-Madeleine",59    _k("Lanaudière"): "Lanaudière",60    _k("Laurentides"): "Laurentides",61    _k("Laval"): "Laval",62    _k("Mauricie"): "Mauricie",63    _k("Montérégie"): "Montérégie",64    _k("Montréal"): "Montréal",65    _k("Outaouais"): "Outaouais",66    _k("Québec"): "Capitale-Nationale",67    _k("Région de Québec"): "Capitale-Nationale",68    _k("Saguenay–Lac-Saint-Jean"): "Saguenay–Lac-Saint-Jean",69}7071# Villes → région administrative. Table PRINCIPALE : data/villes_regions.json,72# générée depuis le Répertoire des municipalités du Québec (MAMH, données73# ouvertes, 1 193 municipalités sans ambiguïté). La table manuelle ci-dessous74# sert de repli et couvre quelques graphies fréquentes des sources.75_VILLES_JSON = None767778def _villes_table() -> dict[str, str]:79    global _VILLES_JSON80    if _VILLES_JSON is None:81        import json82        from pathlib import Path83        p = Path(__file__).resolve().parent.parent / "data" / "villes_regions.json"84        try:85            _VILLES_JSON = json.loads(p.read_text(encoding="utf-8"))["villes"]86        except Exception:87            _VILLES_JSON = {}88    return _VILLES_JSON899091CITY_TO_ADMIN: dict[str, str] = {92    _k(city): region93    for city, region in {94        "Montréal": "Montréal",95        "Québec": "Capitale-Nationale",96        "Lévis": "Chaudière-Appalaches",97        "Laval": "Laval",98        "Gatineau": "Outaouais",99        "Longueuil": "Montérégie",100        "Brossard": "Montérégie",101        "Saint-Jean-sur-Richelieu": "Montérégie",102        "Granby": "Montérégie",103        "Salaberry-de-Valleyfield": "Montérégie",104        "Sorel-Tracy": "Montérégie",105        "Vaudreuil-Dorion": "Montérégie",106        "Sherbrooke": "Estrie",107        "Magog": "Estrie",108        "Bromont": "Estrie",109        "Trois-Rivières": "Mauricie",110        "Shawinigan": "Mauricie",111        "La Tuque": "Mauricie",112        "Saguenay": "Saguenay–Lac-Saint-Jean",113        "Alma": "Saguenay–Lac-Saint-Jean",114        "Roberval": "Saguenay–Lac-Saint-Jean",115        "Dolbeau-Mistassini": "Saguenay–Lac-Saint-Jean",116        "Rimouski": "Bas-Saint-Laurent",117        "Rivière-du-Loup": "Bas-Saint-Laurent",118        "Matane": "Bas-Saint-Laurent",119        "Gaspé": "Gaspésie–Îles-de-la-Madeleine",120        "Percé": "Gaspésie–Îles-de-la-Madeleine",121        "Les Îles-de-la-Madeleine": "Gaspésie–Îles-de-la-Madeleine",122        "Baie-Comeau": "Côte-Nord",123        "Sept-Îles": "Côte-Nord",124        "Rouyn-Noranda": "Abitibi-Témiscamingue",125        "Val-d'Or": "Abitibi-Témiscamingue",126        "Amos": "Abitibi-Témiscamingue",127        "Chibougamau": "Nord-du-Québec",128        "Drummondville": "Centre-du-Québec",129        "Victoriaville": "Centre-du-Québec",130        "Bécancour": "Centre-du-Québec",131        "Joliette": "Lanaudière",132        "Terrebonne": "Lanaudière",133        "Repentigny": "Lanaudière",134        "Mascouche": "Lanaudière",135        "Saint-Jérôme": "Laurentides",136        "Mont-Tremblant": "Laurentides",137        "Blainville": "Laurentides",138        "Saint-Sauveur": "Laurentides",139        "Mirabel": "Laurentides",140        "Saint-Georges": "Chaudière-Appalaches",141        "Thetford Mines": "Chaudière-Appalaches",142        "Montmagny": "Chaudière-Appalaches",143        "Baie-Saint-Paul": "Capitale-Nationale",144        "La Malbaie": "Capitale-Nationale",145        "Wendake": "Capitale-Nationale",146        "L'Ancienne-Lorette": "Capitale-Nationale",147    }.items()148}149150151def region_from_tourist(label: str) -> str:152    """Région administrative à partir d'une région touristique (SITQ/ATR)."""153    return TOURIST_TO_ADMIN.get(_k(label), "")154155156def region_from_city(city: str) -> str:157    """Région administrative à partir d'une ville (MAMH d'abord, repli manuel)."""158    key = _k(city)159    for candidate in (160        key,161        # « St-Damase » → « saint damase », « Ste-Anne » → « sainte anne »162        re.sub(r"\bste\b", "sainte", re.sub(r"\bst\b", "saint", key)),163        # « Sainte-Adèle (secteur X) » / « Québec, arr. de … »164        key.split("(")[0].split(",")[0].strip(),165    ):166        hit = _villes_table().get(candidate) or CITY_TO_ADMIN.get(candidate, "")167        if hit:168            return hit169    return ""170171172def is_valid_region(region: str) -> bool:173    return region in REGIONS174