""" Configuration definition. Converts per-run (environment) variables and config files into the "python world" using `pydantic`. Pydantic models might have convenience methods attached. """ from typing import Optional from pydantic import BaseModel, BaseSettings, root_validator class DavSettings(BaseModel): """ Connection to a DAV server. """ protocol: Optional[str] host: Optional[str] username: Optional[str] password: Optional[str] path: Optional[str] @property def url(self) -> str: """ Combined DAV URL. """ return f"{self.protocol}://{self.host}{self.path}" @classmethod @property def default(cls) -> "DavSettings": return cls( protocol="https", host="example.com", username="ovdashboard", password="secret", ) class Settings(BaseSettings): """ Per-run settings. """ production_mode: bool = False api_v1_prefix: str = "api/v1" openapi_url: str = "/openapi.json" docs_url: Optional[str] = "/docs" redoc_url: Optional[str] = "/redoc" webdav: DavSettings = DavSettings() caldav: DavSettings = DavSettings() cache_seconds: int = 30 class Config: env_nested_delimiter = "__" @root_validator(pre=True) @classmethod def validate_dav_settings(cls, values): # ensure both settings dicts are created for key in ("webdav", "caldav"): if key not in values: values[key] = {} default_dav = DavSettings.default.dict() for key in default_dav: # if "webdav" value is not specified, use default if key not in values["webdav"]: values["webdav"][key] = default_dav[key] # if "caldav" value is not specified, use "webdav" value if key not in values["caldav"]: values["caldav"][key] = values["webdav"][key] # add default "path"s if None if values["webdav"]["path"] is None: values["webdav"]["path"] = "/remote.php/webdav" if values["caldav"]["path"] is None: values["caldav"]["path"] = "/remote.php/dav" return values SETTINGS = Settings(_env_file=".env")