Search code examples
python-3.xsettingspydanticpydantic-settings

Nested settings with pydantic-settings


Using pydantic-settings (v2.0.3), I want to manage settings for services service1 and service2, nesting them under the common settings object, so I can address them like settings.service1.secret1 or settings.service2.secret2. Currently, I have this code in my config.py:

from pydantic_settings import BaseSettings


class FirstServiceSettings(BaseSettings):
    secret1: str


class SecondServiceSettings(BaseSettings):
    secret2: str


class Settings(BaseSettings):
    service1: FirstServiceSettings
    service2: SecondServiceSettings

    class Config:
        env_file = ".env"


settings = Settings()

And this is my .env file:

secret1=secret1
secret2=secret2

However, I'm getting pydantic_core._pydantic_core.ValidationError: 4 validation errors for Settings.

The problem can be solved by adding service1__ and service2__ prefixes to keys in .env file and setting env_nested_delimiter = '__', but I wonder is there a way to make this without adding those prefixes in .env file.


Solution

  • This problem can be solved using BaseModel and set extra='ignore' to BaseSettings:

    from pydantic import BaseModel
    from pydantic_settings import VERSION, BaseSettings, SettingsConfigDict
    
    print(f'{VERSION = }')
    # > VERSION = '2.0.3'
    
    
    class BaseServiceSettings(BaseSettings):
        model_config = SettingsConfigDict(env_file='.env', extra='ignore')
    
    
    class FirstServiceSettings(BaseServiceSettings):
        secret1: str
    
    
    class SecondServiceSettings(BaseServiceSettings):
        secret2: str
    
    
    class Settings2(BaseModel):
        service1: FirstServiceSettings = FirstServiceSettings()
        service2: SecondServiceSettings = SecondServiceSettings()
    
    
    settings = Settings2()
    print(settings.model_dump_json())
    # > {"service1":{"secret1":"secret1"},"service2":{"secret2":"secret2"}}