Coverage for src/kwai/core/settings.py: 97%
97 statements
« prev ^ index » next coverage.py v7.6.10, created at 2024-01-01 00:00 +0000
« prev ^ index » next coverage.py v7.6.10, created at 2024-01-01 00:00 +0000
1"""Module for the settings of this application."""
3import os
4import tomllib
6from functools import lru_cache
7from typing import Annotated, Any, Literal, Optional, Union
9from pydantic import BaseModel, Field
12ENV_SETTINGS_FILE = "KWAI_SETTINGS_FILE"
15class SettingsException(Exception):
16 """Raised when a problem occurred while loading the settings."""
19class ApplicationSettingsModel(BaseModel):
20 """Settings that apply to all applications."""
22 default: bool = False # Set to true for selecting the default application
23 vite_server: str | None = None # Only required in development.
24 variables: dict[str, Any] | None = None
27class AdminApplicationSettings(ApplicationSettingsModel):
28 """Settings for the admin application."""
30 name: Literal["admin"]
33class AuthenticationApplicationSettings(ApplicationSettingsModel):
34 """Settings for the auth application."""
36 name: Literal["auth"]
39class AuthorApplicationSettings(ApplicationSettingsModel):
40 """Settings for the author application."""
42 name: Literal["author"]
45class ClubApplicationSettings(ApplicationSettingsModel):
46 """Settings for the club application."""
48 name: Literal["club"]
51class CoachApplicationSettings(ApplicationSettingsModel):
52 """Settings for the portal application."""
54 name: Literal["coach"]
57class PortalApplicationSettings(ApplicationSettingsModel):
58 """Settings for the portal application."""
60 name: Literal["portal"]
63Application = Annotated[
64 Union[
65 AdminApplicationSettings,
66 AuthenticationApplicationSettings,
67 AuthorApplicationSettings,
68 ClubApplicationSettings,
69 CoachApplicationSettings,
70 PortalApplicationSettings,
71 ],
72 Field(discriminator="name"),
73]
76class FrontendSettings(BaseModel):
77 """Settings for the frontend."""
79 test: bool = False
80 path: str
81 apps: list[Application]
84class FilesSettings(BaseModel):
85 """Settings for files (upload)."""
87 path: str
90class AdminSettings(BaseModel):
91 """Settings for the administrator of the website."""
93 name: str
94 email: str
97class ContactSettings(BaseModel):
98 """Settings for the contact of the club."""
100 street: str
101 city: str
102 email: str
105class WebsiteSettings(BaseModel):
106 """Settings about the website."""
108 url: str
109 email: str
110 name: str
111 copyright: Optional[str] = None
112 admin: Optional[AdminSettings] = None
113 contact: Optional[ContactSettings] = None
116class DatabaseSettings(BaseModel):
117 """Settings for the database connection."""
119 host: str
120 name: str
121 user: str
122 password: str
125class CORSSettings(BaseModel):
126 """Settings for configuring CORS."""
128 origins: list[str] = Field(default_factory=list)
129 methods: list[str] = Field(default_factory=lambda: ["*"])
130 headers: list[str] = Field(default_factory=lambda: ["*"])
133class LoggerSettings(BaseModel):
134 """Settings for the logger."""
136 file: str = "kwai.log"
137 level: str = "DEBUG"
138 retention: str = "7 days"
139 rotation: str = "1 day"
142class EmailSettings(BaseModel):
143 """Settings for sending emails."""
145 host: str
146 port: int
147 ssl: bool = True
148 tls: bool = True
149 user: str | None = None
150 password: str | None = None
151 address: str = Field(alias="from")
154class RedisSettings(BaseModel):
155 """Settings for Redis."""
157 host: str = "127.0.0.1"
158 port: int = 6379
159 password: str | None = None
160 logger: LoggerSettings | None = None
163class SecuritySettings(BaseModel):
164 """Setting or security."""
166 access_token_expires_in: int = 60 # minutes
167 refresh_token_expires_in: int = 43200 # 30 days
168 jwt_algorithm: str = "HS256"
169 jwt_secret: str
170 jwt_refresh_secret: str
173class Settings(BaseModel):
174 """Class with settings."""
176 frontend: FrontendSettings
178 files: FilesSettings
180 security: SecuritySettings
182 logger: LoggerSettings | None = None
184 cors: CORSSettings | None = None
186 db: DatabaseSettings
188 website: WebsiteSettings
190 email: EmailSettings
192 redis: RedisSettings
195@lru_cache
196def get_settings() -> Settings:
197 """Dependency function for creating the Settings instance.
199 The settings are cached with lru_cache, which means the file is only loaded ounce.
201 :raises:
202 core.settings.SettingsException: Raised when the env variable is not set, or
203 when the file
204 can't be read.
205 """
206 if ENV_SETTINGS_FILE in os.environ:
207 settings_file = os.environ.get(ENV_SETTINGS_FILE, "")
208 try:
209 with open(settings_file, mode="rb") as file_handle:
210 return Settings.model_validate(tomllib.load(file_handle))
211 except OSError as exc:
212 raise SettingsException(f"Could not load {settings_file}") from exc
213 raise SettingsException(
214 f"{ENV_SETTINGS_FILE} should be set as environment variable"
215 )