Coverage for packages/kwai-core/src/kwai_core/settings.py: 96%
70 statements
« prev ^ index » next coverage.py v7.11.0, created at 2024-01-01 00:00 +0000
« prev ^ index » next coverage.py v7.11.0, 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 anyio import Path
10from pydantic import BaseModel, Field
13ENV_SETTINGS_FILE = "KWAI_SETTINGS_FILE"
16class SettingsException(Exception):
17 """Raised when a problem occurred while loading the settings."""
20class ApplicationSettingsModel(BaseModel):
21 """Settings that apply to all applications."""
23 default: bool = False # Set to true for selecting the default application
24 vite_server: str | None = None # Only required in development.
25 variables: dict[str, Any] | None = None
28class AdminApplicationSettings(ApplicationSettingsModel):
29 """Settings for the admin application."""
31 name: Literal["admin"]
34class AuthenticationApplicationSettings(ApplicationSettingsModel):
35 """Settings for the auth application."""
37 name: Literal["auth"]
40class AuthorApplicationSettings(ApplicationSettingsModel):
41 """Settings for the author application."""
43 name: Literal["author"]
46class ClubApplicationSettings(ApplicationSettingsModel):
47 """Settings for the club application."""
49 name: Literal["club"]
52class CoachApplicationSettings(ApplicationSettingsModel):
53 """Settings for the portal application."""
55 name: Literal["coach"]
58class PortalApplicationSettings(ApplicationSettingsModel):
59 """Settings for the portal application."""
61 name: Literal["portal"]
64Application = Annotated[
65 Union[
66 AdminApplicationSettings,
67 AuthenticationApplicationSettings,
68 AuthorApplicationSettings,
69 ClubApplicationSettings,
70 CoachApplicationSettings,
71 PortalApplicationSettings,
72 ],
73 Field(discriminator="name"),
74]
77class FrontendSettings(BaseModel):
78 """Settings for the frontend."""
80 test: bool = False
81 path: str
82 apps: list[Application]
85class FilesSettings(BaseModel):
86 """Settings for files (upload)."""
88 path: str
91class AdminSettings(BaseModel):
92 """Settings for the administrator of the website."""
94 name: str
95 email: str
98class ContactSettings(BaseModel):
99 """Settings for the contact of the club."""
101 street: str
102 city: str
103 email: str
106class WebsiteSettings(BaseModel):
107 """Settings about the website."""
109 url: str
110 email: str
111 name: str
112 copyright: Optional[str] = None
113 admin: Optional[AdminSettings] = None
114 contact: Optional[ContactSettings] = None
115 privacy_policy: Optional[str] = None
118class DatabaseSettings(BaseModel):
119 """Settings for the database connection."""
121 host: str
122 name: str
123 user: str
124 password: str
127class CORSSettings(BaseModel):
128 """Settings for configuring CORS."""
130 origins: list[str] = Field(default_factory=list)
131 methods: list[str] = Field(default_factory=lambda: ["*"])
132 headers: list[str] = Field(default_factory=lambda: ["*"])
135class LoggerSettings(BaseModel):
136 """Settings for the logger."""
138 file: os.PathLike[str] = Field(default=Path("kwai.log"))
139 level: str = "DEBUG"
140 retention: str = "7 days"
141 rotation: str = "1 day"
144class EmailSettings(BaseModel):
145 """Settings for sending emails."""
147 host: str
148 port: int
149 ssl: bool = True
150 tls: bool = True
151 user: str | None = None
152 password: str | None = None
153 address: str = Field(alias="from")
156class RedisSettings(BaseModel):
157 """Settings for Redis."""
159 host: str = "127.0.0.1"
160 port: int = 6379
161 password: str | None = None
162 logger: LoggerSettings | None = None
165class GoogleSSOSettings(BaseModel):
166 """Settings for Google SSO."""
168 client_id: str
169 client_secret: str
172class SecuritySettings(BaseModel):
173 """Setting or security."""
175 access_token_expires_in: int = 60 # minutes
176 refresh_token_expires_in: int = 43200 # 30 days
177 jwt_algorithm: str = "HS256"
178 jwt_secret: str
179 jwt_refresh_secret: str
181 google: GoogleSSOSettings | None = None
184class Settings(BaseModel):
185 """Class with settings."""
187 openapi_url: str = "/openapi.json"
189 frontend: FrontendSettings
191 files: FilesSettings
193 security: SecuritySettings
195 logger: LoggerSettings | None = None
197 cors: CORSSettings | None = None
199 db: DatabaseSettings
201 website: WebsiteSettings
203 email: EmailSettings
205 redis: RedisSettings
208@lru_cache
209def get_settings() -> Settings:
210 """Dependency function for creating the Settings instance.
212 The settings are cached with lru_cache, which means the file is only loaded ounce.
214 :raises:
215 kwai_core.settings.SettingsException: Raised when the env variable is not set, or
216 when the file
217 can't be read.
218 """
219 if ENV_SETTINGS_FILE in os.environ:
220 settings_file = os.environ.get(ENV_SETTINGS_FILE, "")
221 try:
222 with open(settings_file, mode="rb") as file_handle:
223 return Settings.model_validate(tomllib.load(file_handle))
224 except OSError as exc:
225 raise SettingsException(f"Could not load {settings_file}") from exc
226 raise SettingsException(
227 f"{ENV_SETTINGS_FILE} should be set as environment variable"
228 )