import pathlib from typing import Any, Self from fansifter_common.adapters.aws.secretsmanager import SecretsManager from fansifter_common.constants import PROD_ENVIRONMENT, QA_ENVIRONMENT from fansifter_common.logging import LogFormat from fansifter_common.logging.utils import update_logging_config from fansifter_common.utils.functional import lazy_proxy from pydantic import Field, ValidationError, model_validator from pydantic_settings import BaseSettings, SettingsConfigDict class Settings(BaseSettings): environment: str debug: bool = Field(validation_alias="APP_DEBUG", default=False) base_dir: pathlib.Path = pathlib.Path(__file__).resolve().parent.parent service_name: str = "lambda-audience-share-audience" service_version: str = "1.0.0" # AWS region configuration aws_region_name: str = "us-east-1" # Google google_developer_token: str = "" google_developer_token_name: str = "" @property def tmp_dir(self) -> pathlib.Path: if self.environment in [QA_ENVIRONMENT, PROD_ENVIRONMENT]: return pathlib.Path("/tmp") return self.base_dir.joinpath("tmp") @property def m2m_token_secret_key_name(self) -> str: return f"{self.environment}/lambda-jwt-refresh/jwt_token" @property def m2m_token_secret_expiry_key_name(self) -> str: return f"{self.environment}/lambda-jwt-refresh/jwt_token_expiration" # KMS kms_key_id: str = Field(default="", validation_alias="DMP_KMS_KEY_ID") # Logging log_format: LogFormat = "json" logging_config: dict[str, Any] = { "version": 1, "disable_existing_loggers": True, "handlers": { "stream": { "level": "INFO", "class": "fansifter_common.logging.OwsStreamHandler", }, }, "loggers": { "app": { "handlers": ["stream"], "level": "INFO", "propagate": False, }, "fansifter_common.httpclient": { "handlers": ["stream"], "level": "WARNING", "propagate": False, }, }, } @model_validator(mode="after") def _setup_logging_config(self) -> Self: self.logging_config = update_logging_config( logging_config=self.logging_config, environment=self.environment, service_name=self.service_name, service_version=self.service_version, log_format=self.log_format, debug=self.debug, ) return self # Sentry sentry_dsn: str | None = None @model_validator(mode="after") def _setup_sentry_dsn(self) -> Self: if not self.sentry_dsn and self.environment in [ QA_ENVIRONMENT, PROD_ENVIRONMENT, ]: raise ValueError(f"Sentry is not configured in {self.environment}.") return self @model_validator(mode="after") def _get_credentials_from_secrets_manager(self) -> Self: if self.environment in [QA_ENVIRONMENT, PROD_ENVIRONMENT]: secrets_manager = SecretsManager(region_name=self.aws_region_name) self.google_developer_token = secrets_manager.get_secret( self.google_developer_token_name ) return self model_config = SettingsConfigDict( env_file=".env", env_file_encoding="utf-8", case_sensitive=False, extra="allow", ) def setup_settings(**defaults: Any) -> Settings: """Setup the application settings.""" try: return Settings(**defaults) except ValidationError as exc: errors = "\n".join( [ f" * {'.'.join(map(str, error['loc']))} - {error['msg']}" for error in exc.errors() ] ) raise RuntimeError(f"Failed to initialize settings:\n {errors}") from exc # Lazy proxy for the settings settings = lazy_proxy(setup_settings)