SmartEDT/backend/config/settings.py

102 lines
3.0 KiB
Python
Raw Normal View History

from __future__ import annotations
import configparser
import os
from dataclasses import dataclass
from pathlib import Path
@dataclass(frozen=True)
class ServerSettings:
host: str = "0.0.0.0"
port: int = 5000
debug: bool = False
@dataclass(frozen=True)
class FileSettings:
root_path: Path
@dataclass(frozen=True)
class DatabaseSettings:
url: str
timescaledb: bool = True
@dataclass(frozen=True)
class AppSettings:
server: ServerSettings
files: FileSettings
database: DatabaseSettings
import sys
def _find_config_file() -> Path | None:
# Handle PyInstaller frozen state
if getattr(sys, 'frozen', False):
# If onefile, _MEIPASS. If onedir, executable dir or _internal
# With onedir, the exe is in root, internal files in _internal.
# But our spec put config in backend/config
# Check relative to executable
exe_dir = Path(sys.executable).parent
candidates = [
exe_dir / "backend" / "config" / "config.ini",
exe_dir / "_internal" / "backend" / "config" / "config.ini",
exe_dir / "config.ini",
]
for path in candidates:
if path.exists():
return path
candidates = [
Path(__file__).resolve().parent / "config.ini",
Path(__file__).resolve().parents[1] / "config.ini",
Path(__file__).resolve().parents[2] / "config.ini",
]
for path in candidates:
if path.exists():
return path
return None
def load_settings() -> AppSettings:
config = configparser.ConfigParser()
config_path = os.getenv("SMARTEDT_CONFIG")
if config_path:
config.read(config_path, encoding="utf-8")
else:
found = _find_config_file()
if found:
config.read(found, encoding="utf-8")
server = ServerSettings(
host=config.get("SERVER", "host", fallback=os.getenv("SMARTEDT_HOST", "0.0.0.0")),
port=config.getint("SERVER", "port", fallback=int(os.getenv("SMARTEDT_PORT", "5000"))),
debug=config.getboolean("SERVER", "debug", fallback=os.getenv("SMARTEDT_DEBUG", "False").lower() == "true"),
)
default_root = Path(os.getenv("SMARTEDT_FILE_ROOT", "data"))
root_value = config.get("FILEPATH", "path", fallback=str(default_root))
root_path = Path(root_value)
if not root_path.is_absolute():
root_path = (Path(__file__).resolve().parents[1] / root_path).resolve()
database_url = config.get("DATABASE", "url", fallback=os.getenv("SMARTEDT_DATABASE_URL", "")).strip()
if not database_url:
database_url = "postgresql+psycopg://smartedt:CHANGE_ME@127.0.0.1:5432/smartedt"
timescaledb = config.getboolean(
"DATABASE",
"timescaledb",
fallback=os.getenv("SMARTEDT_TIMESCALEDB", "True").lower() == "true",
)
return AppSettings(
server=server,
files=FileSettings(root_path=root_path),
database=DatabaseSettings(url=database_url, timescaledb=timescaledb),
)