From 77a579d5edb9557b055c9d6e43f1758236967356 Mon Sep 17 00:00:00 2001 From: Themis Valtinos <73662635+themisvaltinos@users.noreply.github.com> Date: Tue, 1 Jul 2025 20:35:21 +0300 Subject: [PATCH] Chore: Add check for dot env to avoid python env conflicts --- sqlmesh/core/config/loader.py | 6 ++-- tests/core/test_config.py | 60 +++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/sqlmesh/core/config/loader.py b/sqlmesh/core/config/loader.py index f1ef0ed5a7..f40646131d 100644 --- a/sqlmesh/core/config/loader.py +++ b/sqlmesh/core/config/loader.py @@ -37,11 +37,13 @@ def load_configs( for p in (glob.glob(str(path)) or [str(path)]) ] - if dotenv_path: + if dotenv_path and dotenv_path.exists() and dotenv_path.is_file(): load_dotenv(dotenv_path=dotenv_path, override=True) else: for path in absolute_paths: - load_dotenv(dotenv_path=path / ".env", override=True) + env_file = path / ".env" + if env_file.exists() and env_file.is_file(): + load_dotenv(dotenv_path=env_file, override=True) if not isinstance(config, str): if type(config) != config_type: diff --git a/tests/core/test_config.py b/tests/core/test_config.py index dd07c8395f..a33b06eca9 100644 --- a/tests/core/test_config.py +++ b/tests/core/test_config.py @@ -1238,6 +1238,66 @@ def test_load_yaml_config_dot_env_vars(tmp_path_factory): ) +def test_load_config_dotenv_directory_not_loaded(tmp_path_factory): + main_dir = tmp_path_factory.mktemp("config_with_env_dir") + config_path = main_dir / "config.yaml" + with open(config_path, "w", encoding="utf-8") as fd: + fd.write( + """gateways: + test_gateway: + connection: + type: duckdb + database: test.db +model_defaults: + dialect: duckdb +""" + ) + + # Create a .env directory instead of a file to simulate a Python virtual environment + env_dir = main_dir / ".env" + env_dir.mkdir() + (env_dir / "pyvenv.cfg").touch() + + # Also create a regular .env file in another project directory + other_dir = tmp_path_factory.mktemp("config_with_env_file") + other_config_path = other_dir / "config.yaml" + with open(other_config_path, "w", encoding="utf-8") as fd: + fd.write( + """gateways: + test_gateway: + connection: + type: duckdb + database: test.db +model_defaults: + dialect: duckdb +""" + ) + + env_file = other_dir / ".env" + with open(env_file, "w", encoding="utf-8") as fd: + fd.write('TEST_ENV_VAR="from_dotenv_file"') + + # Test that the .env directory doesn't cause an error and is skipped + with mock.patch.dict(os.environ, {}, clear=True): + load_configs( + "config", + Config, + paths=[main_dir], + ) + # Should succeed without loading any env vars from the directory + assert "TEST_ENV_VAR" not in os.environ + + # Test that a real .env file is still loaded properly + with mock.patch.dict(os.environ, {}, clear=True): + load_configs( + "config", + Config, + paths=[other_dir], + ) + # The env var should be loaded from the file + assert os.environ.get("TEST_ENV_VAR") == "from_dotenv_file" + + def test_load_yaml_config_custom_dotenv_path(tmp_path_factory): main_dir = tmp_path_factory.mktemp("yaml_config_2") config_path = main_dir / "config.yaml"