pydantic-settings icon indicating copy to clipboard operation
pydantic-settings copied to clipboard

Support more than one directory for settings management

Open BrettMoan opened this issue 2 years ago • 3 comments

very similar to https://github.com/pydantic/pydantic/issues/2284

I would love to be able to leverage built-in settings configuration, but in order to do that, I need support for both ConfigMaps and Secrets

i don't know if a file per setting is absolutely necessary, but it would be great if instead of a secrets_dir: str|None you had a directories: List[str]|None or search_dirs: List[str]|None argument, where settings were loaded by iterating over 1..N directories using much the same logic as today.

beyond just allowing use of both ConfigMaps and Secrets, this could then produce conflicts, which instead of a defect, would actually be a very handy a feature, it allows for overrides (such as when running locally) this can be accomplished by having the expectation that the last found match wins.

class Settings(BaseSettings):
    my_secret_data: str
    my_not_secret_data: str
    my_overridden_data: str


    class Config:
        search_dirs = [ '/run/config' ,   '/run/secrets', ]

with files

/run/config/my_not_secret_data # foo
/run/config/my_overridden_data # bar
/run/secrets/my_overridden_data # baz
/run/secrets/my_secret_data # fu

pragmatic expectation: all 4 files get opened/read/parsed/validated

resulting object is

s = Settings() # s.my_secret_data == 'fu', s.my_not_secret_data == 'foo', s.my_overridden_data == 'baz', 

BrettMoan avatar Sep 22 '22 06:09 BrettMoan

Thanks, looks reasonable to me :+1:.

samuelcolvin avatar Sep 22 '22 08:09 samuelcolvin

May I throw in 2¢ – perhaps a more flexible approach would be to expose sources as a Config parameter? E. g. something like:

from pydantic_settings import default_sources, BaseSettings

class Settings(BaseSettings):
    my_secret_data: str
    class Config:
        sources = [
            *default_sources,
            SecretsSettingsSource('/run/config'),
            SecretsSettingsSource('/run/secrets'),
        ]

This would need some changes in how settings sources are initialized (I think we can pass settings_cls at the time Config is defined, but it would look a bit clunky?).

As an upside, it will allow specifying third-party sources more easily:

class Config:
    sources = [*default_sources, MyFeatureFlagsProviderSource(...)]

notpushkin avatar Apr 26 '23 10:04 notpushkin

I'd also second that sources should be configurable via Config as having to implement .settings_customise_sources() is very verbose for simple use cases.

stereobutter avatar Jul 28 '23 08:07 stereobutter