HTML 82.1%
Python 14.6%
TypeScript 1.9%
CSS 1%
JavaScript 0.5%
1# =============================================================================2# Job·Ka — Groupe KA3# Auteur : Simon-Pierre Boucher4# Contact : contact@spboucher.ai5# Fichier : jobka/regions.py6# Rôle : Région administrative du Québec (17 régions) depuis la ville —7# répertoire MAMH embarqué (data/regions-qc.json) + arrondissements8# Créé : 2026-08-19 Modifié : 2026-08-199# =============================================================================10"""Dérivation de la région administrative (17 régions du Québec).1112Source : Répertoire des municipalités du MAMH (données ouvertes, colonne13`regadm`), figé dans ``data/regions-qc.json`` (~1 260 entrées : municipalités14+ arrondissements/quartiers fréquents dans les libellés d'offres). Clé de15recherche : nom de ville minuscules sans accents. Ville inconnue -> "" —16jamais de région inventée.17"""18from __future__ import annotations1920import json21from functools import lru_cache22from pathlib import Path2324from .normalize import canonical_city, strip_accents2526_DATA_PATH = Path(__file__).resolve().parent.parent / "data" / "regions-qc.json"2728# Les 17 régions administratives (référence pour validation/affichage)29REGIONS_QC = (30 "Abitibi-Témiscamingue", "Bas-Saint-Laurent", "Capitale-Nationale",31 "Centre-du-Québec", "Chaudière-Appalaches", "Côte-Nord", "Estrie",32 "Gaspésie–Îles-de-la-Madeleine", "Lanaudière", "Laurentides", "Laval",33 "Mauricie", "Montérégie", "Montréal", "Nord-du-Québec", "Outaouais",34 "Saguenay–Lac-Saint-Jean",35)363738@lru_cache(maxsize=1)39def _mapping() -> dict[str, str]:40 try:41 return json.loads(_DATA_PATH.read_text(encoding="utf-8"))42 except (OSError, ValueError):43 return {}444546def _key(city: str) -> str:47 return " ".join(strip_accents((city or "").lower()).split())484950def city_from_slug_tokens(tokens: list[str]) -> str:51 """Plus long préfixe de `tokens` (segments d'un slug d'URL) qui forme une52 municipalité québécoise connue — résout « Pointe-Claire-Analyste-… » où53 ville et titre partagent le même séparateur « - ». Retourne la ville54 reconstituée (« Pointe-Claire »), ou "" si aucun préfixe ne correspond.55 """56 from .normalize import _QC_CITIES # table des libellés fréquents57 table = _mapping()58 for n in range(min(len(tokens), 5), 0, -1):59 raw = "-".join(t for t in tokens[:n] if t)60 k = _key(raw)61 k2 = k.replace("st-", "saint-").replace("ste-", "sainte-")62 if k in table or k2 in table or k in _QC_CITIES or k2 in _QC_CITIES:63 return raw64 return ""656667def region_for_city(city: str) -> str:68 """Ville -> région administrative (« Montérégie »…), ou "" si inconnue.6970 La ville est d'abord canonicalisée (« Quebec City » -> « Québec ») ; les71 préfixes de type « Ville de » sont tolérés.72 """73 if not city:74 return ""75 table = _mapping()76 for candidate in (canonical_city(city), city):77 k = _key(candidate)78 if not k:79 continue80 if k in table:81 return table[k]82 # « ville de sherbrooke », « st-jerome » (st- = saint-)83 k2 = k.removeprefix("ville de ").replace("st-", "saint-") \84 .replace("ste-", "sainte-")85 if k2 in table:86 return table[k2]87 return ""88