Repository: pydantic/pydantic-settings

Issue:
Don't spit env vars if env_nested_delimiter=None
By default `env_nested_delimiter=None` but this value is not special-cased, leading to surprising (if not ourtight buggy) behavior with `case_sensitive=True`:

```python
    class Subsettings(BaseSettings):
        foo: str

    class Settings(BaseSettings):
        subsettings: Subsettings

        model_config = SettingsConfigDict(case_sensitive=True)

    env.set('subsettingsNonefoo', 'abc')
    s = Settings()
    assert s.subsettings.foo == 'abc'
```

Hints from issue comments:
@hramezani: Thanks @gsakkis for reporting this issue.

The above example code that you provided returns `pydantic_settings.sources.SettingsError` before [your last commit](https://github.com/pydantic/pydantic-settings/commit/ccf99b2d78803f001930ef11e7ebefb1ec30d173). that behavior was wrong but could be fixed by putting the below code at the beginning of function:

```py
        if not self.env_nested_delimiter:
            return {}
```

This block of code can also fix the problem after you commit but I am afraid your change breaks people's code.
It would be great if you can take a look and provide a fix otherwise I will make a fix later.


Solution patch:
diff --git a/pydantic_settings/sources.py b/pydantic_settings/sources.py
index 4d719cc..bd4f431 100644
--- a/pydantic_settings/sources.py
+++ b/pydantic_settings/sources.py
@@ -908,6 +908,9 @@ class EnvSettingsSource(PydanticBaseEnvSettingsSource):
         Returns:
             A dictionary contains extracted values from nested env values.
         """
+        if not self.env_nested_delimiter:
+            return {}
+
         is_dict = lenient_issubclass(get_origin(field.annotation), dict)
 
         prefixes = [


Test patch:
diff --git a/tests/test_settings.py b/tests/test_settings.py
index d63f2b7..ba793a8 100644
--- a/tests/test_settings.py
+++ b/tests/test_settings.py
@@ -858,6 +858,25 @@ def test_case_sensitive(monkeypatch):
     ]
 
 
+@pytest.mark.parametrize('env_nested_delimiter', [None, ''])
+def test_case_sensitive_no_nested_delimiter(monkeypatch, env_nested_delimiter):
+    class Subsettings(BaseSettings):
+        foo: str
+
+    class Settings(BaseSettings):
+        subsettings: Subsettings
+
+        model_config = SettingsConfigDict(case_sensitive=True, env_nested_delimiter=env_nested_delimiter)
+
+    # Need to patch os.environ to get build to work on Windows, where os.environ is case insensitive
+    monkeypatch.setattr(os, 'environ', value={'subsettingsNonefoo': '1'})
+    with pytest.raises(ValidationError) as exc_info:
+        Settings()
+    assert exc_info.value.errors(include_url=False) == [
+        {'type': 'missing', 'loc': ('subsettings',), 'msg': 'Field required', 'input': {}}
+    ]
+
+
 def test_nested_dataclass(env):
     @pydantic_dataclasses.dataclass
     class DeepNestedDataclass: