♻️ Use pydantic-settings to handle config file

This commit is contained in:
2023-09-09 23:34:04 +02:00
parent 4056b3a739
commit bfc669cd11
2 changed files with 51 additions and 32 deletions

View File

@@ -1,6 +1,14 @@
from typing import Any from __future__ import annotations
from pydantic import BaseModel, BaseSettings, Field, root_validator, SecretStr from typing import Annotated
from pydantic import BaseModel, SecretStr
from pydantic.functional_validators import model_validator
from pydantic_settings import (
BaseSettings,
PydanticBaseSettingsSource,
SettingsConfigDict,
)
class HttpSettings(BaseModel): class HttpSettings(BaseModel):
@@ -9,28 +17,13 @@ class HttpSettings(BaseModel):
cert: str | None = None cert: str | None = None
def check_user_password(cls, values: dict[str, Any]) -> dict[str, Any]:
user = values.get("user")
password = values.get("password")
if user is not None and password is None:
raise ValueError("user is set, password shall be set too.")
if password is not None and user is None:
raise ValueError("password is set, user shall be set too.")
return values
class DatabaseSettings(BaseModel): class DatabaseSettings(BaseModel):
name: str = "carrramba-encore-rate" name: str
host: str = "127.0.0.1" host: str
port: int = 5432 port: int
driver: str = "postgresql+psycopg" driver: str = "postgresql+psycopg"
user: str | None = None user: str
password: SecretStr | None = None password: Annotated[SecretStr, check_user_password]
_user_password_validation = root_validator(allow_reuse=True)(check_user_password)
class CacheSettings(BaseModel): class CacheSettings(BaseModel):
@@ -38,9 +31,18 @@ class CacheSettings(BaseModel):
host: str = "127.0.0.1" host: str = "127.0.0.1"
port: int = 6379 port: int = 6379
user: str | None = None user: str | None = None
password: SecretStr | None = None password: Annotated[SecretStr | None, check_user_password] = None
_user_password_validation = root_validator(allow_reuse=True)(check_user_password)
@model_validator(mode="after")
def check_user_password(self) -> DatabaseSettings | CacheSettings:
if self.user is not None and self.password is None:
raise ValueError("user is set, password shall be set too.")
if self.password is not None and self.user is None:
raise ValueError("password is set, user shall be set too.")
return self
class TracingSettings(BaseModel): class TracingSettings(BaseModel):
@@ -50,10 +52,23 @@ class TracingSettings(BaseModel):
class Settings(BaseSettings): class Settings(BaseSettings):
app_name: str app_name: str
idfm_api_key: SecretStr = Field(..., env="IDFM_API_KEY") idfm_api_key: SecretStr
clear_static_data: bool = Field(False, env="CLEAR_STATIC_DATA") clear_static_data: bool
http: HttpSettings = HttpSettings() http: HttpSettings
db: DatabaseSettings = DatabaseSettings() db: DatabaseSettings
cache: CacheSettings = CacheSettings() cache: CacheSettings
tracing: TracingSettings = TracingSettings() tracing: TracingSettings
model_config = SettingsConfigDict(env_prefix="CER__", env_nested_delimiter="__")
@classmethod
def settings_customise_sources(
cls,
settings_cls: type[BaseSettings],
init_settings: PydanticBaseSettingsSource,
env_settings: PydanticBaseSettingsSource,
dotenv_settings: PydanticBaseSettingsSource,
file_secret_settings: PydanticBaseSettingsSource,
) -> tuple[PydanticBaseSettingsSource, ...]:
return env_settings, init_settings, file_secret_settings

View File

@@ -9,7 +9,7 @@ readme = "README.md"
python = "^3.11" python = "^3.11"
aiohttp = "^3.8.3" aiohttp = "^3.8.3"
aiofiles = "^22.1.0" aiofiles = "^22.1.0"
fastapi = "^0.95.0" fastapi = "^0.103.0"
uvicorn = "^0.20.0" uvicorn = "^0.20.0"
msgspec = "^0.12.0" msgspec = "^0.12.0"
opentelemetry-instrumentation-fastapi = "^0.38b0" opentelemetry-instrumentation-fastapi = "^0.38b0"
@@ -23,11 +23,12 @@ sqlalchemy = "^2.0.12"
psycopg = "^3.1.9" psycopg = "^3.1.9"
pyyaml = "^6.0" pyyaml = "^6.0"
fastapi-cache2 = {extras = ["redis"], version = "^0.2.1"} fastapi-cache2 = {extras = ["redis"], version = "^0.2.1"}
pydantic-settings = "^2.0.3"
[tool.poetry.group.db_updater.dependencies] [tool.poetry.group.db_updater.dependencies]
aiofiles = "^22.1.0" aiofiles = "^22.1.0"
aiohttp = "^3.8.3" aiohttp = "^3.8.3"
fastapi = "^0.95.0" fastapi = "^0.103.0"
msgspec = "^0.12.0" msgspec = "^0.12.0"
opentelemetry-instrumentation-fastapi = "^0.38b0" opentelemetry-instrumentation-fastapi = "^0.38b0"
opentelemetry-instrumentation-sqlalchemy = "^0.38b0" opentelemetry-instrumentation-sqlalchemy = "^0.38b0"
@@ -41,11 +42,14 @@ pyyaml = "^6.0"
sqlalchemy = "^2.0.12" sqlalchemy = "^2.0.12"
sqlalchemy-utils = "^0.41.1" sqlalchemy-utils = "^0.41.1"
tqdm = "^4.65.0" tqdm = "^4.65.0"
pydantic-settings = "^2.0.3"
[build-system] [build-system]
requires = ["poetry-core"] requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api" build-backend = "poetry.core.masonry.api"
[tool.poetry.group.dev.dependencies] [tool.poetry.group.dev.dependencies]
pylsp-mypy = "^0.6.2" pylsp-mypy = "^0.6.2"
mccabe = "^0.7.0" mccabe = "^0.7.0"