使用 pydantic-settings 将平面环境变量映射到嵌套 Pydantic 模型

问题描述 投票:0回答:1

我的应用程序有 YAML 配置和环境变量,并且我正在使用 pydantic-settings 将 YAML 和环境变量加载到我的 Pydantic 模型中。 Pydantic 应该更喜欢 env var 而不是 yaml。

但是,我面临嵌套模型的问题,其中环境变量结构与我的嵌套 Pydantic 模型字段不一致。

这是我的 config.yaml:

mongodb:
  host: "mongo"
  port: 27017
  username: "USER"
  password: "123456"
  name: "db"
  collection: "tasks"

s3:
  bucket_name: "ai"

我的代码如下所示:

import os
from pydantic_settings import YamlConfigSettingsSource, BaseSettings, PydanticBaseSettingsSource, EnvSettingsSource
from typing import Tuple, Type
from pydantic import BaseModel


class DatabaseSettings(BaseModel):
    host: str
    port: int
    username: str
    password: str
    name: str
    collection: str


class S3Settings(BaseModel):
    bucket_name: str


class Settings(BaseSettings):
    mongodb: DatabaseSettings
    s3: S3Settings

    @classmethod
    def settings_customise_sources(
            cls, settings_cls: Type[BaseSettings], **kwargs
    ) -> Tuple[PydanticBaseSettingsSource, ...]:
        return (
            EnvSettingsSource(
                settings_cls,
                env_nested_delimiter="_",
                case_sensitive=False,
                env_prefix="PREFIX_"
            ),
            YamlConfigSettingsSource(settings_cls, yaml_file="config.yaml"),
        )


db_host = os.environ.get('PREFIX_MONGODB_HOST')
if db_host is not None:
    print(f"PREFIX_MONGODB_HOST is set to: {db_host}")
else:
    print("PREFIX_MONGODB_HOST is not set")

s3_bucket_name = os.environ.get('PREFIX_S3_BUCKET_NAME')
if s3_bucket_name is not None:
    print(f"PREFIX_S3_BUCKET_NAME is set to: {s3_bucket_name}")
else:
    print("PREFIX_S3_BUCKET_NAME is not set")

settings = Settings()
print(settings.model_dump())

我定义了以下环境变量:

PREFIX_MONGODB_HOST=本地主机

PREFIX_S3_BUCKET_NAME=某个存储桶

当我运行此代码时,输出是:

```
PREFIX_MONGODB_HOST is set to: localhost
PREFIX_S3_BUCKET_NAME is set to: some-bucket
{'mongodb': {'host': 'localhost', 'port': 27017, 'username': 'USER', 'password': '123456', 'name': 'db', 'collection': 'tasks'}, 's3': {'bucket_name': 'ai'}}
```

问题:

PREFIX_MONGODB_HOST 正确覆盖 YAML 中的 mongodb.host 键。但是,PREFIX_S3_BUCKET_NAME 不会覆盖 s3.bucket_name。问题似乎是 pydantic-settings 将环境变量 PREFIX_S3_BUCKET_NAME 解析为以下 json:

{
  "s3": {
    "bucket": {
      "name": "some-bucket"
    }
  }
}

这与我的 pydantic 模型不相符。

我希望它将环境变量解析为:

{
  "s3": {
    "bucket_name": "some-bucket"
  }
}

这与 pydantic 模型相对应。 我无法更改环境变量名称 (PREFIX_S3_BUCKET_NAME),因此我正在寻找面向 pydantic-settings 的解决方案来将此环境变量映射到 S3Settings 模型中的 bucket_name 字段。

我尝试过使用别名和不同的配置,但到目前为止没有任何效果。

希望得到任何帮助:)

python yaml environment-variables pydantic pydantic-settings
1个回答
0
投票

Pydantic 无法猜测

_
何时是层次结构分隔符以及何时
_
是属性名称的一部分。您需要选择一个明确的层次结构分隔符,例如,
__
:

class Settings(BaseSettings):
    mongodb: DatabaseSettings
    s3: S3Settings

    @classmethod
    def settings_customise_sources(
        cls, settings_cls: Type[BaseSettings], **kwargs
    ) -> Tuple[PydanticBaseSettingsSource, ...]:
        return (
            EnvSettingsSource(
                settings_cls,
                env_nested_delimiter="__",
                case_sensitive=False,
                env_prefix="PREFIX_",
            ),
            YamlConfigSettingsSource(settings_cls, yaml_file="config.yaml"),
        )

然后您可以设置:

PREFIX_MONGODB__HOST=localhost
PREFIX_S3__BUCKET_NAME=some-bucket

你会得到:

{'mongodb': {'host': 'localhost', 'port': 27017, 'username': 'USER', 'password': '123456', 'name': 'db', 'collection': 'tasks'}, 's3': {'bucket_name': 'some-bucket'}}
© www.soinside.com 2019 - 2024. All rights reserved.