feat: config externe à côté de l'exe — mise à jour sans recompiler

Au premier lancement, la config embarquée est copiée dans config/
à côté de l'exe. Les lancements suivants utilisent cette copie externe.

Workflow de mise à jour :
1. L'établissement exporte ses paramètres (JSON)
2. On fusionne avec merge_params.py
3. On leur envoie le nouveau dictionnaires.yml par email
4. Ils le déposent dans config/ à côté de l'exe
5. Aucune recompilation nécessaire

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-30 18:09:02 +02:00
parent 898ad9d82d
commit b2ee6ad835

View File

@@ -22,6 +22,7 @@ import queue
import re import re
import shutil import shutil
import subprocess import subprocess
import sys
import threading import threading
from dataclasses import dataclass, field from dataclasses import dataclass, field
from pathlib import Path from pathlib import Path
@@ -89,10 +90,39 @@ APP_TITLE = "Pseudonymisation de vos documents"
APP_VERSION = "v5.4" APP_VERSION = "v5.4"
def _app_dir() -> Path: def _app_dir() -> Path:
"""Répertoire racine de l'application (compatible Nuitka standalone).""" """Répertoire racine de l'application (compatible PyInstaller/Nuitka)."""
if getattr(sys, 'frozen', False):
return Path(sys._MEIPASS)
return Path(__file__).resolve().parent return Path(__file__).resolve().parent
DEFAULT_CFG = _app_dir() / "config" / "dictionnaires.yml" def _exe_dir() -> Path:
"""Répertoire de l'exécutable (pour les fichiers persistants : config, logs)."""
if getattr(sys, 'frozen', False):
return Path(sys.executable).parent
return Path(__file__).resolve().parent
def _resolve_config() -> Path:
"""Cherche la config en priorité à côté de l'exe, sinon dans l'app embarquée.
Si le fichier n'existe pas à côté de l'exe, copie la version embarquée
pour que l'utilisateur puisse la modifier sans recompiler.
"""
exe_cfg = _exe_dir() / "config" / "dictionnaires.yml"
app_cfg = _app_dir() / "config" / "dictionnaires.yml"
if exe_cfg.exists():
return exe_cfg
# Premier lancement : copier la config embarquée à côté de l'exe
if app_cfg.exists():
exe_cfg.parent.mkdir(parents=True, exist_ok=True)
import shutil
shutil.copy2(str(app_cfg), str(exe_cfg))
return exe_cfg
return app_cfg # fallback
DEFAULT_CFG = _resolve_config()
MODELS_DIR = _app_dir() / "models" MODELS_DIR = _app_dir() / "models"
DEFAULTS_CFG_TEXT = r""" DEFAULTS_CFG_TEXT = r"""