Files
notytex/backend/core/config.py
Bertrand Benjamin 2b08eb534a Migration v1 (Flask) -> v2 (FastAPI + Vue.js) complétée
 Changements majeurs:
- Suppression complète du code Flask legacy
- Migration backend FastAPI vers racine /backend
- Migration frontend Vue.js vers racine /frontend
- Suppression de notytex-v2/ (code monté à la racine)

 Validations:
- Backend démarre correctement (port 8000)
- API /api/v2/health répond healthy
- 99/99 tests unitaires passent
- Frontend configuré avec proxy Vite

📝 Documentation:
- README.md réécrit pour v2
- Instructions de démarrage mises à jour
- .gitignore adapté pour backend/frontend/

🎯 Architecture finale:
notytex/
├── backend/     # FastAPI + SQLAlchemy + Pydantic
├── frontend/    # Vue 3 + Vite + TailwindCSS
├── docs/        # Documentation
└── school_management.db  # Base de données (inchangée)

Jalon 6 complété: Application v2 prête pour utilisation!
2025-11-25 21:09:47 +01:00

118 lines
3.8 KiB
Python

"""
Configuration de l'application avec pydantic-settings.
"""
from functools import lru_cache
from pathlib import Path
from typing import Optional
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
"""Configuration de l'application."""
# Application
app_name: str = "Notytex API"
app_version: str = "2.0.0"
debug: bool = False
# Database - deux modes de configuration:
# 1. database_path: chemin simple vers le fichier SQLite (recommandé)
# 2. database_url: URL complète SQLAlchemy (rétrocompatibilité)
# Si database_url est défini, il a la priorité sur database_path
database_path: Optional[str] = None
database_url: Optional[str] = None
def _resolve_database_path(self) -> Path:
"""Résout le chemin de la base de données."""
if self.database_url:
# Extraire le chemin depuis l'URL SQLAlchemy
# Format: sqlite+aiosqlite:///path ou sqlite+aiosqlite:////absolute/path
url = self.database_url
# Retirer le préfixe
for prefix in ["sqlite+aiosqlite://", "sqlite://"]:
if url.startswith(prefix):
url = url[len(prefix):]
break
# Le chemin commence par / ou // pour absolu, ou rien pour relatif
return Path(url).resolve()
elif self.database_path:
path = Path(self.database_path)
if not path.is_absolute():
# Par défaut, relatif au répertoire du projet
path = Path(__file__).parent.parent / self.database_path
return path.resolve()
else:
# Valeur par défaut
return (Path(__file__).parent.parent / "school_management.db").resolve()
def get_database_url(self) -> str:
"""Retourne l'URL de connexion async pour SQLAlchemy."""
if self.database_url is not None and self.database_url.startswith("sqlite"):
return self.database_url
# Construire depuis le chemin
path = self._resolve_database_path()
return f"sqlite+aiosqlite:///{path}"
@property
def sync_database_url(self) -> str:
"""Retourne l'URL de base de données synchrone."""
return self.get_database_url().replace("sqlite+aiosqlite://", "sqlite://")
@property
def database_path_resolved(self) -> Path:
"""Retourne le chemin absolu résolu de la base de données."""
return self._resolve_database_path()
@property
def database_path_configured(self) -> str:
"""Retourne le chemin tel que configuré (pour affichage)."""
if self.database_url:
# Extraire depuis l'URL
return str(self._resolve_database_path())
return self.database_path or "school_management.db"
@property
def database_exists(self) -> bool:
"""Vérifie si le fichier de base de données existe."""
return self.database_path_resolved.exists()
# API
api_v2_prefix: str = "/api/v2"
# CORS
cors_origins: list[str] = ["http://localhost:3000", "http://localhost:5173"]
# Logging
log_level: str = "INFO"
log_format: str = "json"
# Email (repris de v1)
smtp_server: Optional[str] = None
smtp_port: int = 587
smtp_username: Optional[str] = None
smtp_password: Optional[str] = None
smtp_use_tls: bool = True
email_from: Optional[str] = None
model_config = SettingsConfigDict(
env_file=".env",
env_file_encoding="utf-8",
case_sensitive=False,
extra="ignore",
)
@lru_cache()
def get_settings() -> Settings:
"""
Récupère les settings (cached).
Utilise lru_cache pour éviter de relire le fichier .env à chaque appel.
"""
return Settings()
# Export pour faciliter l'import
settings = get_settings()