-
-
Notifications
You must be signed in to change notification settings - Fork 89
Settings Merging from files doesn't allow for partial overrides #590
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Thanks @rfenner for reporting this.
Yes
Agree, we can add a flag for this. Also, you can create a custom toml settings source like bellow: from typing import Any
from pathlib import Path
from pydantic._internal._utils import deep_update
from pydantic_settings import (
BaseSettings,
PydanticBaseSettingsSource,
SettingsConfigDict,
TomlConfigSettingsSource,
)
from pydantic_settings.sources import PathType
class MyTomlConfigSettingsSource(TomlConfigSettingsSource):
def _read_files(self, files: PathType | None) -> dict[str, Any]:
vars: dict[str, Any] = {}
for file in files:
file_path = Path(file).expanduser()
if file_path.is_file():
vars = deep_update(vars, self._read_file(file_path))
return vars
class Settings(BaseSettings):
db: dict[str, Any]
model_config = SettingsConfigDict(toml_file=('main.toml', 'override.toml'))
@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 (MyTomlConfigSettingsSource(settings_cls),)
print(Settings()) |
Thanks for pointing out how to do it. I was able to implement the merging from your suggestion. I had another idea on how to do it but one that would have loaded it outside and provide the data to the settings class and you solution works better |
I would also note that it would be nice to be able to merge data from config files and init_settings. Right now the data from files overwrites any collections in init_settings. For example: class Settings(BaseSettings):
... # add yaml config file source
data: dict[str, int] = {
'foo': 10,
'bar': 20,
} # settings.yaml config file
data:
bar: 30 And finally we get: >>> s = Settings()
>>> print(s)
Settings(data={'bar': 30}) But I'd like to get: Settings(data={'foo': 10, 'bar': 30}) It would be nice to be able to customize merge strategies for different collections such as lists and dictionaries. |
I wrote a class to simulate the .dotenv loading of toml files where it generated the list of toml files to load in.
The problem I discovered is that the file merging is shallow ie if you have two files that both specify the same header key if you stry to override just one setting in the header from the previous file's version it wipes everything else out.
example
main.toml
override.toml
The data that gets loaded and then validated is
instead of
This is because the _read_files in ConfigFileSourceMixin uses the update methods of the dict which just replaces the value if the key already exists.
It would be nice to add a function that could recessively merge the dicts together that may one could do partial overrides. Thi affects all the other loaders like yaml and json as well.
The text was updated successfully, but these errors were encountered: