from pathlib import Path from typing import Any, Tuple, Type import yaml from pydantic_settings import BaseSettings, InitSettingsSource, PydanticBaseSettingsSource, SettingsConfigDict from pydantic_settings.sources import ConfigFileSourceMixin, EnvSettingsSource def parse_cors(v: Any) -> list[str] | str: if isinstance(v, str) and not v.startswith("["): return [i.strip() for i in v.split(",")] elif isinstance(v, list | str): return v raise ValueError(v) class ProjectBaseSettings(BaseSettings): model_config = SettingsConfigDict(yaml_file="envs.yml", yaml_file_encoding="utf-8", env_prefix="service") @classmethod def settings_customise_sources( cls, settings_cls: Type[BaseSettings], init_settings: PydanticBaseSettingsSource, env_settings: EnvSettingsSource, # type: ignore dotenv_settings: PydanticBaseSettingsSource, file_secret_settings: PydanticBaseSettingsSource, ) -> Tuple[PydanticBaseSettingsSource, ...]: return ( init_settings, PrefixedYamlConfigSettingsSource(env_settings.env_prefix, settings_cls), env_settings, file_secret_settings, ) class PrefixedYamlConfigSettingsSource(InitSettingsSource, ConfigFileSourceMixin): def __init__(self, prefix: str, settings_cls: type[BaseSettings]): self.yaml_file_path = "envs.yml" self.yaml_file_encoding = "utf-8" self.yaml_data = self._read_files(self.yaml_file_path)[prefix] super().__init__(settings_cls, self.yaml_data) def _read_file(self, file_path: Path) -> dict[str, dict[str, Any]]: with open(file_path, encoding=self.yaml_file_encoding) as yaml_file: return yaml.safe_load(yaml_file)