/
Befun
/
FamalyControlle
Обзор
Документация
Войти
/
Befun
/
FamalyControlle
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
config.py
127 строк
4 KB
BeFun
Init project
07 май 2026, 10:43
07 май 2026, 10:43
7e96900
Код
Авторство
О чём код?
""" Модуль управления конфигурацией. Загружает config.yaml и предоставляет доступ к настройкам через Config singleton. """ import os from pathlib import Path from typing import Any, Optional import yaml class _Config: """Singleton для доступа к конфигурации.""" _instance: Optional["_Config"] = None _data: dict[str, Any] = {} def __new__(cls) -> "_Config": if cls._instance is None: cls._instance = super().__new__(cls) return cls._instance # ── Загрузка ────────────────────────────────────────────── def load(self, path: Optional[str] = None) -> None: """Загрузить config.yaml. Если путь не указан — ищет в CWD и рядом со скриптом.""" if path is None: candidates = [ Path("config.yaml"), Path(__file__).resolve().parent.parent / "config.yaml", ] for c in candidates: if c.exists(): path = str(c) break if path and Path(path).exists(): with open(path, "r", encoding="utf-8") as f: self._data = yaml.safe_load(f) or {} else: self._data = {} # ── Доступ ──────────────────────────────────────────────── @property def raw(self) -> dict[str, Any]: return self._data def get(self, dotted_key: str, default: Any = None) -> Any: """Получить значение по ключу 'section.subkey'.""" keys = dotted_key.split(".") value: Any = self._data for k in keys: if isinstance(value, dict): value = value.get(k) if value is None: return default else: return default return value # ── Удобные свойства ────────────────────────────────────── @property def max_bot_token(self) -> str: return self.get("max_bot.token", "") @property def max_bot_api_base(self) -> str: return self.get("max_bot.api_base", "https://api.max.ru/v1") @property def max_bot_poll_interval(self) -> int: return int(self.get("max_bot.poll_interval", 3)) @property def admin_max_user_id(self) -> str: return self.get("admin.max_user_id", "") @property def server_host(self) -> str: return self.get("server.host", "0.0.0.0") @property def server_port(self) -> int: return int(self.get("server.port", 8642)) @property def database_url(self) -> str: url = self.get("server.database_url", "sqlite:///./data/family_control.db") # Убедимся, что директория для SQLite существует if url.startswith("sqlite:///"): db_dir = Path(url.removeprefix("sqlite:///")).parent db_dir.mkdir(parents=True, exist_ok=True) return url @property def agent_poll_interval(self) -> int: return int(self.get("agent.poll_interval", 2)) @property def agent_server_url(self) -> str: return self.get("agent.server_url", "http://localhost:8642") @property def block_categories(self) -> dict[str, list[str]]: cats = self.get("block_categories", {}) result: dict[str, list[str]] = {} for category, entries in cats.items(): if isinstance(entries, list): result[category] = [e.lower() for e in entries] elif isinstance(entries, dict): # Для downloads: extensions — это подсписок for sub_key, sub_val in entries.items(): if isinstance(sub_val, list): result[f"{category}.{sub_key}"] = [v.lower() for v in sub_val] return result @property def download_dirs(self) -> list[str]: raw = self.get("agent.download_dirs", []) return [os.path.expanduser(d) for d in raw] # Глобальный экземпляр Config = _Config()