diff --git a/pydantic_settings/sources/providers/dotenv.py b/pydantic_settings/sources/providers/dotenv.py index d953f5f0..9816588f 100644 --- a/pydantic_settings/sources/providers/dotenv.py +++ b/pydantic_settings/sources/providers/dotenv.py @@ -109,7 +109,7 @@ def __call__(self) -> dict[str, Any]: # As `extra` config is allowed in dotenv settings source, We have to # update data with extra env variables from dotenv file. for env_name, env_value in self.env_vars.items(): - if not env_value or env_name in data: + if not env_value or env_name in data or (self.env_prefix and env_name in self.settings_cls.model_fields): continue env_used = False for field_name, field in self.settings_cls.model_fields.items(): diff --git a/tests/test_settings.py b/tests/test_settings.py index 8e845ff1..0cb50d29 100644 --- a/tests/test_settings.py +++ b/tests/test_settings.py @@ -3000,6 +3000,61 @@ class Settings(BaseSettings): assert s.model_dump() == {'foo': 'test-foo'} +def test_dotenv_env_prefix_env_without_prefix_ignored(tmp_path): + p = tmp_path / '.env' + p.write_text('foo=foo') + + class Settings(BaseSettings): + model_config = SettingsConfigDict( + env_file=p, + env_prefix='TEST_', + extra='ignore', + ) + + foo: str = '' + + s = Settings() + assert s.model_dump() == {'foo': ''} + + +def test_nested_model_dotenv_env_prefix_env_without_prefix_ignored(tmp_path): + p = tmp_path / '.env' + p.write_text('foo__val=1') + + class Foo(BaseModel): + val: int = 0 + + class Settings(BaseSettings): + model_config = SettingsConfigDict( + env_nested_delimiter='__', + env_file=p, + env_prefix='TEST_', + extra='ignore', + ) + + foo: Foo = Foo() + + s = Settings() + assert s.model_dump() == {'foo': {'val': 0}} + + +def test_dotenv_env_prefix_env_with_alias_without_prefix(tmp_path): + p = tmp_path / '.env' + p.write_text('FooAlias=foo') + + class Settings(BaseSettings): + model_config = SettingsConfigDict( + env_file=p, + env_prefix='TEST_', + extra='ignore', + ) + + foo: str = Field('xxx', alias='FooAlias') + + s = Settings() + assert s.model_dump() == {'foo': 'foo'} + + def test_parsing_secret_field(env): class Settings(BaseSettings): foo: Secret[int]