agnes-the-ai-analyst/config/loader.py
Petr c56905d34f Initial commit: OSS data distribution platform
Open-source AI data analyst platform extracted from internal repo.
Includes data sync engine, Keboola adapter, Flask web portal,
server deployment scripts, and configuration templates.
2026-03-08 23:31:28 +01:00

104 lines
2.7 KiB
Python

"""
Instance configuration loader.
Loads instance.yaml from CONFIG_DIR (env var) or ./config/ fallback.
Used by both webapp and src modules for instance-specific settings.
"""
import logging
import os
from pathlib import Path
from typing import Any
import yaml
logger = logging.getLogger(__name__)
CONFIG_DIR = Path(os.environ.get("CONFIG_DIR", "./config"))
def load_instance_config() -> dict[str, Any]:
"""Load instance configuration from instance.yaml.
Search order:
1. $CONFIG_DIR/instance.yaml
2. ./config/instance.yaml
Raises:
FileNotFoundError: If instance.yaml not found.
yaml.YAMLError: If YAML is invalid.
ValueError: If config is empty or missing required fields.
"""
path = CONFIG_DIR / "instance.yaml"
if not path.exists():
# Fallback to local config dir
path = Path("./config/instance.yaml")
if not path.exists():
raise FileNotFoundError(
"Instance configuration not found. "
"Copy config/instance.yaml.example to config/instance.yaml "
"and fill in your values."
)
with open(path) as f:
config = yaml.safe_load(f)
if not config:
raise ValueError("instance.yaml is empty")
_validate_config(config)
logger.info("Instance config loaded from %s", path)
return config
def _validate_config(config: dict) -> None:
"""Validate required configuration fields.
Raises:
ValueError: If required fields are missing or empty.
"""
required_paths = [
("instance", "name"),
("auth", "allowed_domain"),
("server", "host"),
("server", "hostname"),
]
missing = []
for keys in required_paths:
value = config
path_str = ".".join(keys)
for key in keys:
if not isinstance(value, dict) or key not in value:
missing.append(path_str)
break
value = value[key]
else:
if not value:
missing.append(path_str)
if missing:
raise ValueError(
f"Missing required instance config fields: {', '.join(missing)}. "
f"Check config/instance.yaml"
)
def get_instance_value(config: dict, *keys: str, default: Any = None) -> Any:
"""Get a nested value from instance config.
Args:
config: Instance config dict.
*keys: Path of keys (e.g., "instance", "name").
default: Default value if path not found.
Returns:
Config value or default.
"""
value = config
for key in keys:
if not isinstance(value, dict) or key not in value:
return default
value = value[key]
return value if value is not None else default