mirror of
https://github.com/fastapi-practices/fastapi_best_architecture.git
synced 2026-03-13 09:31:31 +08:00
Allow to add config in plugin toml (#1033)
This commit is contained in:
@@ -5,9 +5,10 @@ from re import Pattern
|
||||
from typing import Any, Literal
|
||||
|
||||
from pydantic import model_validator
|
||||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||
from pydantic_settings import BaseSettings, PydanticBaseSettingsSource, SettingsConfigDict
|
||||
|
||||
from backend.core.path_conf import ENV_EXAMPLE_FILE_PATH, ENV_FILE_PATH
|
||||
from backend.plugin.settings_source import PluginSettingsSource
|
||||
|
||||
|
||||
class Settings(BaseSettings):
|
||||
@@ -16,10 +17,22 @@ class Settings(BaseSettings):
|
||||
model_config = SettingsConfigDict(
|
||||
env_file=ENV_FILE_PATH,
|
||||
env_file_encoding='utf-8',
|
||||
extra='ignore',
|
||||
extra='allow',
|
||||
case_sensitive=True,
|
||||
)
|
||||
|
||||
@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, dotenv_settings, PluginSettingsSource(settings_cls)
|
||||
|
||||
# .env 当前环境
|
||||
ENVIRONMENT: Literal['dev', 'prod']
|
||||
|
||||
|
||||
39
backend/plugin/settings_source.py
Normal file
39
backend/plugin/settings_source.py
Normal file
@@ -0,0 +1,39 @@
|
||||
import os
|
||||
|
||||
from typing import Any
|
||||
|
||||
import rtoml
|
||||
|
||||
from pydantic.fields import FieldInfo
|
||||
from pydantic_settings import PydanticBaseSettingsSource
|
||||
|
||||
from backend.core.path_conf import PLUGIN_DIR
|
||||
|
||||
|
||||
class PluginSettingsSource(PydanticBaseSettingsSource):
|
||||
"""从所有插件的 plugin.toml 加载配置的自定义配置源"""
|
||||
|
||||
def get_field_value(self, field: FieldInfo, field_name: str) -> tuple[Any, str, bool]:
|
||||
"""获取单个字段的值"""
|
||||
# 不在这里实现,使用 __call__ 批量加载
|
||||
return None, field_name, False
|
||||
|
||||
def __call__(self) -> dict[str, Any]:
|
||||
"""加载所有插件配置"""
|
||||
merged_settings: dict[str, Any] = {}
|
||||
|
||||
for item in os.listdir(PLUGIN_DIR):
|
||||
item_path = PLUGIN_DIR / item
|
||||
if not os.path.isdir(item_path):
|
||||
continue
|
||||
if '__init__.py' not in os.listdir(item_path):
|
||||
continue
|
||||
|
||||
toml_path = item_path / 'plugin.toml'
|
||||
if toml_path.exists():
|
||||
with open(toml_path, encoding='utf-8') as f:
|
||||
config = rtoml.load(f)
|
||||
plugin_settings = config.get('settings', {})
|
||||
merged_settings.update(plugin_settings)
|
||||
|
||||
return merged_settings
|
||||
Reference in New Issue
Block a user