Skip to content

Commit e066774

Browse files
authored
Fix a bug when we have case insentive field in nested model (#294)
1 parent 6d25cee commit e066774

File tree

2 files changed

+29
-3
lines changed

2 files changed

+29
-3
lines changed

pydantic_settings/sources.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -274,14 +274,24 @@ class Settings(BaseSettings):
274274
for name, value in field_values.items():
275275
sub_model_field: FieldInfo | None = None
276276

277+
annotation = field.annotation
278+
279+
# If field is Optional, we need to find the actual type
280+
args = get_args(annotation)
281+
if origin_is_union(get_origin(field.annotation)) and len(args) == 2 and type(None) in args:
282+
for arg in args:
283+
if arg != type(None):
284+
annotation = arg
285+
break
286+
277287
# This is here to make mypy happy
278288
# Item "None" of "Optional[Type[Any]]" has no attribute "model_fields"
279-
if not field.annotation or not hasattr(field.annotation, 'model_fields'):
289+
if not annotation or not hasattr(annotation, 'model_fields'):
280290
values[name] = value
281291
continue
282292

283293
# Find field in sub model by looking in fields case insensitively
284-
for sub_model_field_name, f in field.annotation.model_fields.items():
294+
for sub_model_field_name, f in annotation.model_fields.items():
285295
if not f.validation_alias and sub_model_field_name.lower() == name.lower():
286296
sub_model_field = f
287297
break
@@ -337,7 +347,7 @@ def __call__(self) -> dict[str, Any]:
337347
field_value = None
338348
if (
339349
not self.case_sensitive
340-
and lenient_issubclass(field.annotation, BaseModel)
350+
# and lenient_issubclass(field.annotation, BaseModel)
341351
and isinstance(field_value, dict)
342352
):
343353
data[field_key] = self._replace_field_names_case_insensitively(field, field_value)

tests/test_settings.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2648,3 +2648,19 @@ class Settings(BaseSettings):
26482648
)
26492649
s = Settings()
26502650
assert s.model_dump() == {'nested': {'foo': 'string'}}
2651+
2652+
2653+
def test_case_insensitive_nested_optional(env):
2654+
class NestedSettings(BaseModel):
2655+
FOO: str
2656+
BaR: int
2657+
2658+
class Settings(BaseSettings):
2659+
model_config = SettingsConfigDict(env_nested_delimiter='__', case_sensitive=False)
2660+
2661+
nested: Optional[NestedSettings]
2662+
2663+
env.set('nested__FoO', 'string')
2664+
env.set('nested__bar', '123')
2665+
s = Settings()
2666+
assert s.model_dump() == {'nested': {'BaR': 123, 'FOO': 'string'}}

0 commit comments

Comments
 (0)