""" File with environment variables and general configuration logic. `SECRET_KEY`, `ENVIRONMENT` etc. map to env variables with the same names. Pydantic priority ordering: 1. (Most important, will overwrite everything) - environment variables 2. `.env` file in root folder of project 3. Default values For project name, version, description we use pyproject.toml For the rest, we use file `.env` (gitignored), see `.env.example` See https://pydantic-docs.helpmanual.io/usage/settings/ Note, complex types like lists are read as json-encoded strings. """ import tomllib from pathlib import Path from typing import Literal from pydantic import AnyHttpUrl, EmailStr from pydantic_settings import BaseSettings, SettingsConfigDict PROJECT_DIR = Path(__file__).parent.parent.parent with open(f"{PROJECT_DIR}/pyproject.toml", "rb") as f: PYPROJECT_CONTENT = tomllib.load(f)["tool"]["poetry"] def build_postgreuri( scheme: str, username: str, password: str, host: str, port: int = 0, path: str = "" ): fullhost = host + (f":{port}" if port > 0 else "") return f"{scheme}://{username}:{password}@{fullhost}{path}" class Settings(BaseSettings): # CORE SETTINGS SECRET_KEY: str ENVIRONMENT: Literal["DEV", "PYTEST", "STG", "PRD"] = "DEV" SECURITY_BCRYPT_ROUNDS: int = 12 ACCESS_TOKEN_EXPIRE_MINUTES: int = 11520 # 8 days REFRESH_TOKEN_EXPIRE_MINUTES: int = 40320 # 28 days BACKEND_CORS_ORIGINS: list[AnyHttpUrl | Literal["*"]] = [] ALLOWED_HOSTS: list[str] = ["localhost", "127.0.0.1"] INACTIVITY_SMS_SENDER_THRESHOLD_SECONDS:int = 180 # PROJECT NAME, VERSION AND DESCRIPTION PROJECT_NAME: str = PYPROJECT_CONTENT["name"] VERSION: str = PYPROJECT_CONTENT["version"] DESCRIPTION: str = PYPROJECT_CONTENT["description"] # POSTGRESQL DEFAULT DATABASE DEFAULT_DATABASE_HOSTNAME: str DEFAULT_DATABASE_USER: str DEFAULT_DATABASE_PASSWORD: str DEFAULT_DATABASE_PORT: str DEFAULT_DATABASE_DB: str @property def DEFAULT_SQLALCHEMY_DATABASE_URI(self) -> str: return build_postgreuri( scheme="postgresql", username=self.DEFAULT_DATABASE_USER, password=self.DEFAULT_DATABASE_PASSWORD, host=self.DEFAULT_DATABASE_HOSTNAME, port=int(self.DEFAULT_DATABASE_PORT), path=f"/{self.DEFAULT_DATABASE_DB}", ) # POSTGRESQL TEST DATABASE TEST_DATABASE_HOSTNAME: str = "postgres" TEST_DATABASE_USER: str = "postgres" TEST_DATABASE_PASSWORD: str = "postgres" TEST_DATABASE_PORT: str = "5432" TEST_DATABASE_DB: str = "postgres" @property def TEST_SQLALCHEMY_DATABASE_URI(self) -> str: return build_postgreuri( scheme="postgresql", username=self.TEST_DATABASE_USER, password=self.TEST_DATABASE_PASSWORD, host=self.TEST_DATABASE_HOSTNAME, port=int(self.TEST_DATABASE_PORT), path=f"/{self.TEST_DATABASE_DB}", ) # SMS batch BATCH_SMS_PHONE_NUMBER: str = "" # FIRST SUPERUSER FIRST_SUPERUSER_EMAIL: EmailStr FIRST_SUPERUSER_PASSWORD: str model_config = SettingsConfigDict(env_file=f"{PROJECT_DIR}/.env", case_sensitive=True) settings: Settings = Settings() # type: ignore