Skip to content
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

Nested Settings with instances of models as defaults #345

Closed
mrijken opened this issue Jul 15, 2024 · 2 comments · Fixed by #348
Closed

Nested Settings with instances of models as defaults #345

mrijken opened this issue Jul 15, 2024 · 2 comments · Fixed by #348
Assignees

Comments

@mrijken
Copy link

mrijken commented Jul 15, 2024

When I have the next Models:

from pydantic import BaseModel
from pydantic_settings import BaseSettings


class DatabaseSettings(BaseModel):
    name: str = "test"
    env: str = "test"


class Settings(BaseSettings):
    db1: DatabaseSettings = DatabaseSettings(name="database1")
    db2: DatabaseSettings = DatabaseSettings(name="database2")


print(Settings(db1={"env": "prd"}))

I will get:

db1=DatabaseSettings(name='test', env='prd') db2=DatabaseSettings(name='database2', env='test')

However, I would expect:

db1=DatabaseSettings(name='database1', env='prd') db2=DatabaseSettings(name='database2', env='test')

I have written a small PydanticBaseSettingsSource fixes this behavior:

class FromClsSettings(pydantic_settings.PydanticBaseSettingsSource):
    def get_field_value(self, **kwargs) -> None:  # type: ignore[override]  # noqa: ANN003
        pass

    def __call__(self) -> dict[str, Any]:
        data = {}
        for field, field_info in self.settings_cls.model_fields.items():
            if isinstance(field_info.default, pydantic.BaseModel):
                data[field] = field_info.default.model_dump()
        return data

Is the issue the expected behavior? Is the proposed solution the correct one? Shall I make a PR?

@mrijken mrijken changed the title Nested Settings with duplicate models Nested Settings with instances of models as defaults Jul 15, 2024
@hramezani
Copy link
Member

Thanks @mrijken for reporting this.

Actually, this is the correct behavior. you have db1: DatabaseSettings = DatabaseSettings(name="database1") in your model. it means the default value for db1 is DatabaseSettings(name="database1", env="test"). when you pass {"env": "prd"}, it will override the default with DatabaseSettings(name='test', env='prd')

@kschwab
Copy link
Contributor

kschwab commented Aug 21, 2024

Hi @mrijken, I've added a flag nested_model_default_partial_update that enables partial updates for default model objects. Could you help verify it resolves your issue and post a simple test for your use case? I believe the case posted in the description is now resolved:

from pydantic import BaseModel
from pydantic_settings import BaseSettings


class DatabaseSettings(BaseModel):
    name: str = 'test'
    env: str = 'test'


class Settings(BaseSettings, nested_model_default_partial_update=True):
    db1: DatabaseSettings = DatabaseSettings(name='database1')
    db2: DatabaseSettings = DatabaseSettings(name='database2')


print(Settings(db1={'env': 'prd'}))
#> db1=DatabaseSettings(name='database1', env='prd') db2=DatabaseSettings(name='database2', env='test')

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants