Skip to content

Commit 2784a70

Browse files
kschwabKyle Schwab
andauthored
Allow nested env var source to override nested init source. (#204)
Co-authored-by: Kyle Schwab <[email protected]>
1 parent 4f24fad commit 2784a70

File tree

2 files changed

+40
-3
lines changed

2 files changed

+40
-3
lines changed

pydantic_settings/sources.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@
77
from collections import deque
88
from dataclasses import is_dataclass
99
from pathlib import Path
10-
from typing import TYPE_CHECKING, Any, List, Mapping, Sequence, Tuple, Union, cast
10+
from typing import TYPE_CHECKING, Any, Dict, List, Mapping, Sequence, Tuple, Union, cast
1111

1212
from dotenv import dotenv_values
13-
from pydantic import AliasChoices, AliasPath, BaseModel, Json
13+
from pydantic import AliasChoices, AliasPath, BaseModel, Json, TypeAdapter
1414
from pydantic._internal._typing_extra import origin_is_union
1515
from pydantic._internal._utils import deep_update, lenient_issubclass
1616
from pydantic.fields import FieldInfo
@@ -121,7 +121,7 @@ def get_field_value(self, field: FieldInfo, field_name: str) -> tuple[Any, str,
121121
return None, '', False
122122

123123
def __call__(self) -> dict[str, Any]:
124-
return self.init_kwargs
124+
return TypeAdapter(Dict[str, Any]).dump_python(self.init_kwargs)
125125

126126
def __repr__(self) -> str:
127127
return f'InitSettingsSource(init_kwargs={self.init_kwargs!r})'

tests/test_settings.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -619,6 +619,43 @@ def settings_customise_sources(
619619
assert s.bar == 'env setting'
620620

621621

622+
def test_env_deep_override(env):
623+
class DeepSubModel(BaseModel):
624+
v4: str
625+
626+
class SubModel(BaseModel):
627+
v1: str
628+
v2: bytes
629+
v3: int
630+
deep: DeepSubModel
631+
632+
class Settings(BaseSettings, env_nested_delimiter='__'):
633+
v0: str
634+
sub_model: SubModel
635+
636+
@classmethod
637+
def settings_customise_sources(
638+
cls, settings_cls, init_settings, env_settings, dotenv_settings, file_secret_settings
639+
):
640+
return env_settings, dotenv_settings, init_settings, file_secret_settings
641+
642+
env.set('SUB_MODEL__DEEP__V4', 'override-v4')
643+
644+
s_final = {'v0': '0', 'sub_model': {'v1': 'init-v1', 'v2': b'init-v2', 'v3': 3, 'deep': {'v4': 'override-v4'}}}
645+
646+
s = Settings(v0='0', sub_model={'v1': 'init-v1', 'v2': b'init-v2', 'v3': 3, 'deep': {'v4': 'init-v4'}})
647+
assert s.model_dump() == s_final
648+
649+
s = Settings(v0='0', sub_model=SubModel(v1='init-v1', v2=b'init-v2', v3=3, deep=DeepSubModel(v4='init-v4')))
650+
assert s.model_dump() == s_final
651+
652+
s = Settings(v0='0', sub_model=SubModel(v1='init-v1', v2=b'init-v2', v3=3, deep={'v4': 'init-v4'}))
653+
assert s.model_dump() == s_final
654+
655+
s = Settings(v0='0', sub_model={'v1': 'init-v1', 'v2': b'init-v2', 'v3': 3, 'deep': DeepSubModel(v4='init-v4')})
656+
assert s.model_dump() == s_final
657+
658+
622659
def test_config_file_settings_nornir(env):
623660
"""
624661
See https://github.com/pydantic/pydantic/pull/341#issuecomment-450378771

0 commit comments

Comments
 (0)