Source code for structum_lab.config.manager

# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: 2025 PythonWoods

"""
Provider di configurazione JSON per Structum.

Questa implementazione rappresenta il fallback minimale basato esclusivamente
sulla standard library Python. È pensata per garantire un funzionamento
immediato del framework in assenza di plugin avanzati.

Per casi d’uso complessi (multi-source, validazione, override per ambiente)
si raccomanda l’uso di provider esterni come Dynaconf.
"""

import json
from pathlib import Path
from typing import Any

CONFIG_DIR = Path.home() / ".structum"
CONFIG_FILE = CONFIG_DIR / "config.json"


[docs] class JSONConfigProvider: """ Provider di configurazione basato su file JSON. Caratteristiche: - Persistenza automatica su filesystem - Supporto a chiavi annidate tramite dot notation - Nessuna dipendenza esterna """
[docs] def __init__(self) -> None: self._data: dict[str, Any] = {} self._ensure_config_dir() self.reload()
def _ensure_config_dir(self) -> None: """Assicura l’esistenza della directory di configurazione.""" CONFIG_DIR.mkdir(parents=True, exist_ok=True)
[docs] def get(self, key: str, default: Any = None) -> Any: """Restituisce il valore associato a una chiave (dot notation supportata).""" value: Any = self._data for part in key.split("."): if isinstance(value, dict) and part in value: value = value[part] else: return default return value
[docs] def set(self, key: str, value: Any) -> None: """Imposta una chiave di configurazione e salva immediatamente su disco.""" data = self._data parts = key.split(".") for part in parts[:-1]: if part not in data or not isinstance(data[part], dict): data[part] = {} data = data[part] data[parts[-1]] = value self.save()
[docs] def has(self, key: str) -> bool: """Verifica l’esistenza di una chiave di configurazione.""" value: Any = self._data for part in key.split("."): if isinstance(value, dict) and part in value: value = value[part] else: return False return True
[docs] def save(self) -> None: """Scrive la configurazione corrente su file JSON.""" self._ensure_config_dir() CONFIG_FILE.write_text(json.dumps(self._data, indent=2))
[docs] def reload(self) -> None: """Ricarica la configurazione dal file JSON gestendo errori di corruzione.""" if not CONFIG_FILE.exists(): self._data = {"plugins": {}} self.save() return try: content = CONFIG_FILE.read_text() # Gestione file vuoto o whitespace if not content.strip(): self._data = {"plugins": {}} self.save() return self._data = json.loads(content) except (json.JSONDecodeError, OSError) as e: # Strategia: Backup del file corrotto e reset # In un framework reale, qui si loggherebbe un warning backup_path = CONFIG_FILE.with_suffix(".json.bak") CONFIG_FILE.rename(backup_path) print( f"⚠️ Configurazione corrotta! Backup salvato in {backup_path}. Reset impostazioni." ) self._data = {"plugins": {}} self.save()