Skip to content

Commit 38d2a2a

Browse files
authored
Release 1.10.3 (#2204)
Bug Fixes * (back-ported) Fix resolution of ``packages-install-path`` when it uses ``env_var`` by @tatiana in #2194
1 parent c2ea9c4 commit 38d2a2a

4 files changed

Lines changed: 84 additions & 2 deletions

File tree

CHANGELOG.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
Changelog
22
=========
33

4+
1.10.3 (2025-12-16)
5+
-------------------
6+
7+
Bug Fixes
8+
9+
* (back-ported) Fix resolution of ``packages-install-path`` when it uses ``env_var`` by @tatiana in #2194
10+
11+
412
1.10.2 (2025-08-08)
513
---------------------
614

cosmos/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
from cosmos import settings
1111

12-
__version__ = "1.10.2"
12+
__version__ = "1.10.3"
1313

1414
if not settings.enable_memory_optimised_imports:
1515
from cosmos.airflow.dag import DbtDag

cosmos/dbt/project.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from typing import Generator
88

99
import yaml
10+
from jinja2 import Template
1011

1112
from cosmos.constants import (
1213
DBT_DEFAULT_PACKAGES_FOLDER,
@@ -40,6 +41,27 @@ def has_non_empty_dependencies_file(project_path: Path) -> bool:
4041
return False
4142

4243

44+
def _resolve_env_var(template_str: str) -> str:
45+
"""
46+
Given a Jinja template string, resolve the environment variables, declared using the dbt syntax,
47+
and return the rendered string.
48+
49+
Example:
50+
- template_str = '/usr/local/airflow/dags/dbt/dbt_packages{{ "_" + env_var("env","") if env_var("env","")!="" }}'
51+
- environment variable `env` is set to "test"
52+
53+
Then, the rendered string will be:
54+
'/usr/local/airflow/dags/dbt/dbt_packages_test'
55+
"""
56+
57+
def env_var(name: str, default: str = "") -> str:
58+
return os.getenv(name, default)
59+
60+
template = Template(template_str)
61+
rendered = template.render(env_var=env_var)
62+
return rendered
63+
64+
4365
def get_dbt_packages_subpath(source_folder: Path) -> str:
4466
"""
4567
Return the dbt project's package installation sub path.
@@ -64,7 +86,7 @@ def get_dbt_packages_subpath(source_folder: Path) -> str:
6486
logger.info(f"Unable to read the {DBT_PROJECT_FILENAME} file")
6587
else:
6688
subpath = dbt_project_file_content.get("packages-install-path", DBT_DEFAULT_PACKAGES_FOLDER)
67-
return subpath
89+
return _resolve_env_var(subpath)
6890

6991

7092
def copy_dbt_packages(source_folder: Path, target_folder: Path) -> None:

tests/dbt/test_project.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
from cosmos.constants import DBT_DEFAULT_PACKAGES_FOLDER, DBT_PROJECT_FILENAME, PACKAGE_LOCKFILE_YML
99
from cosmos.dbt.project import (
10+
_resolve_env_var,
1011
change_working_directory,
1112
copy_dbt_packages,
1213
copy_manifest_file_if_exists,
@@ -78,6 +79,57 @@ def test_returns_custom_path_when_defined(tmpdir):
7879
assert result == "custom_dbt_packages"
7980

8081

82+
@patch.dict(os.environ, {"MY_PATH": "custom_packages"})
83+
def test_resolve_env_var_with_simple_env_var():
84+
"""Test _resolve_env_var with and without a simple env_var reference."""
85+
86+
result = _resolve_env_var("dbt_packages")
87+
assert result == "dbt_packages"
88+
89+
result = _resolve_env_var('{{ env_var("MY_PATH") }}')
90+
assert result == "custom_packages"
91+
92+
93+
@patch.dict(os.environ, {}, clear=False)
94+
def test_resolve_env_var_with_default_value():
95+
"""Test _resolve_env_var with env_var default when variable is not set."""
96+
# Ensure the variable is not set
97+
os.environ.pop("NONEXISTENT_VAR", None)
98+
result = _resolve_env_var('{{ env_var("NONEXISTENT_VAR", "default_path") }}')
99+
assert result == "default_path"
100+
101+
102+
@patch.dict(os.environ, {"dbt_packages_suffix": "test"})
103+
def test_resolve_env_var_with_complex_template():
104+
"""Test _resolve_env_var with complex conditional templates."""
105+
template = 'dbt_packages{{ "_" + env_var("dbt_packages_suffix","") if env_var("dbt_packages_suffix","")!="" }}'
106+
result = _resolve_env_var(template)
107+
assert result == "dbt_packages_test"
108+
109+
os.environ.pop("dbt_packages_suffix", None)
110+
template = 'dbt_packages{{ "_" + env_var("dbt_packages_suffix","") if env_var("dbt_packages_suffix","")!="" }}'
111+
result = _resolve_env_var(template)
112+
assert result == "dbt_packages"
113+
114+
115+
@patch.dict(os.environ, {}, clear=False)
116+
def test_resolve_env_var_with_complex_template_unset_var():
117+
"""Test _resolve_env_var with a complex conditional template when variable is not set."""
118+
if "dbt_packages_suffix" in os.environ:
119+
del os.environ["dbt_packages_suffix"]
120+
template = 'dbt_packages{{ "_" + env_var("dbt_packages_suffix","") if env_var("dbt_packages_suffix","")!="" }}'
121+
result = _resolve_env_var(template)
122+
assert result == "dbt_packages"
123+
124+
125+
@patch.dict(os.environ, {"ENV_SUFFIX": "prod"})
126+
def test_get_dbt_packages_subpath_with_env_var_template(tmpdir):
127+
"""Test get_dbt_packages_subpath with env_var in packages-install-path."""
128+
write_dbt_project_yml(tmpdir, {"packages-install-path": 'dbt_packages_{{ env_var("ENV_SUFFIX") }}'})
129+
result = get_dbt_packages_subpath(tmpdir)
130+
assert result == "dbt_packages_prod"
131+
132+
81133
def test_create_symlinks(tmp_path):
82134
"""Tests that symlinks are created for expected files in the dbt project directory."""
83135
tmp_dir = tmp_path / "dbt-project"

0 commit comments

Comments
 (0)