from functools import lru_cache from pydantic import Field, field_validator from pydantic_settings import BaseSettings, SettingsConfigDict def split_usernames(raw: str) -> list[str]: usernames: list[str] = [] seen: set[str] = set() for part in raw.split(","): username = part.strip() if not username or username in seen: continue seen.add(username) usernames.append(username) return usernames class Settings(BaseSettings): model_config = SettingsConfigDict(env_file=".env", case_sensitive=False) github_username: str = Field(alias="GITHUB_USERNAME") github_token: str | None = Field(default=None, alias="GITHUB_TOKEN") gitea_base_url: str = Field(alias="GITEA_BASE_URL") gitea_username: str = Field(alias="GITEA_USERNAME") gitea_token: str | None = Field(default=None, alias="GITEA_TOKEN") cache_ttl_seconds: int | None = Field(default=None, alias="CACHE_TTL_SECONDS") cache_dir: str | None = Field(default=None, alias="CACHE_DIR") default_theme: str = Field(default="light", alias="DEFAULT_THEME") service_title: str = Field(default="git-activity-merge", alias="SERVICE_TITLE") @field_validator("github_username", "gitea_username") @classmethod def _validate_username_list(cls, value: str) -> str: if not split_usernames(value): raise ValueError("must contain at least one username") return value @property def github_usernames(self) -> list[str]: return split_usernames(self.github_username) @property def gitea_usernames(self) -> list[str]: return split_usernames(self.gitea_username) @lru_cache(maxsize=1) def get_settings() -> Settings: return Settings()