diff --git a/changes/1803-PrettyWood.md b/changes/1803-PrettyWood.md new file mode 100644 index 0000000..f7671cb --- /dev/null +++ b/changes/1803-PrettyWood.md @@ -0,0 +1 @@ +Support home directory relative paths for `dotenv` files (e.g. `~/.env`). \ No newline at end of file diff --git a/pydantic/env_settings.py b/pydantic/env_settings.py index 59ed44b..6846e10 100644 --- a/pydantic/env_settings.py +++ b/pydantic/env_settings.py @@ -58,7 +58,7 @@ class BaseSettings(BaseModel): env_file = _env_file if _env_file != env_file_sentinel else self.__config__.env_file env_file_encoding = _env_file_encoding if _env_file_encoding is not None else self.__config__.env_file_encoding if env_file is not None: - env_path = Path(env_file) + env_path = Path(env_file).expanduser() if env_path.is_file(): env_vars = { **read_env_file( diff --git a/tests/test_settings.py b/tests/test_settings.py index d24aae3..25e88ac 100644 --- a/tests/test_settings.py +++ b/tests/test_settings.py @@ -1,4 +1,6 @@ import os +import uuid +from pathlib import Path from typing import Dict, List, Optional, Set import pytest @@ -547,6 +549,28 @@ def test_env_file_config_custom_encoding(tmp_path): assert s.pika == 'p!±@' +@pytest.fixture +def home_tmp(): + tmp_filename = f'{uuid.uuid4()}.env' + home_tmp_path = Path.home() / tmp_filename + yield home_tmp_path, tmp_filename + home_tmp_path.unlink() + + +@pytest.mark.skipif(not dotenv, reason='python-dotenv not installed') +def test_env_file_home_directory(home_tmp): + home_tmp_path, tmp_filename = home_tmp + home_tmp_path.write_text('pika=baz') + + class Settings(BaseSettings): + pika: str + + class Config: + env_file = f'~/{tmp_filename}' + + assert Settings().pika == 'baz' + + @pytest.mark.skipif(not dotenv, reason='python-dotenv not installed') def test_env_file_none(tmp_path): p = tmp_path / '.env'