Skip to content

Commit 37da708

Browse files
committed
fix: Correct casting of run-operation args to str
When running a macro without arguments using DbtRunOperationOperator the args parameter was set to None. However, dbt always expects a string. So, now we always cast to string and have set the default to "{}", that matches dbt's default.
1 parent c85a189 commit 37da708

File tree

7 files changed

+69
-25
lines changed

7 files changed

+69
-25
lines changed

airflow_dbt_python/__version__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
__author__ = "Tomás Farías Santana"
33
__copyright__ = "Copyright 2021 Tomás Farías Santana"
44
__title__ = "airflow-dbt-python"
5-
__version__ = "0.14.4"
5+
__version__ = "0.14.5"

airflow_dbt_python/hooks/dbt.py

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -85,18 +85,18 @@ def __eq__(self, other):
8585
return Enum.__eq__(self, other)
8686

8787

88-
def parse_vars(vars: Optional[Union[str, dict[str, Any]]]) -> dict[str, Any]:
89-
"""Parse CLI vars as dbt would.
88+
def parse_yaml_args(args: Optional[Union[str, dict[str, Any]]]) -> dict[str, Any]:
89+
"""Parse YAML arguments as dbt would.
9090
9191
This means:
92-
- When vars is a string, we treat it as a YAML dict str.
92+
- When args is a string, we treat it as a YAML dict str.
9393
- If it's already a dictionary, we just return it.
9494
- Otherwise (it's None), we return an empty dictionary.
9595
"""
96-
if isinstance(vars, str):
97-
return yaml_helper.load_yaml_text(vars)
98-
elif isinstance(vars, dict):
99-
return vars
96+
if isinstance(args, str):
97+
return yaml_helper.load_yaml_text(args)
98+
elif isinstance(args, dict):
99+
return args
100100
else:
101101
return {}
102102

@@ -169,7 +169,7 @@ def __post_init__(self):
169169
Raises:
170170
ValueError: When setting two mutually exclusive parameters.
171171
"""
172-
self.parsed_vars = parse_vars(self.vars)
172+
self.parsed_vars = parse_yaml_args(self.vars)
173173
self.vars = yaml.dump(self.parsed_vars)
174174

175175
mutually_exclusive_attrs = (
@@ -555,16 +555,15 @@ class RunTaskConfig(TableMutabilityConfig):
555555
class RunOperationTaskConfig(BaseConfig):
556556
"""Dbt run-operation task arguments."""
557557

558-
args: Optional[str] = None
558+
args: str = "{}"
559559
cls: BaseTask = dataclasses.field(default=RunOperationTask, init=False)
560560
macro: Optional[str] = None
561561
which: str = dataclasses.field(default="run-operation", init=False)
562562

563563
def __post_init__(self):
564564
"""Support dictionary args by casting them to str after setting."""
565565
super().__post_init__()
566-
if isinstance(self.args, dict):
567-
self.args = str(self.args)
566+
self.args = str(self.args)
568567

569568

570569
@dataclass

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "airflow-dbt-python"
3-
version = "0.14.4"
3+
version = "0.14.5"
44
description = "A dbt operator and hook for Airflow"
55
authors = ["Tomás Farías Santana <tomas@tomasfarias.dev>"]
66
license = "MIT"

tests/conftest.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -488,13 +488,30 @@ def snapshot_files(dbt_project_dir):
488488

489489

490490
@pytest.fixture
491-
def macro_file(dbt_project_dir):
491+
def macro_name(dbt_project_dir):
492492
"""Create a dbt macro file."""
493493
d = dbt_project_dir / "macros"
494494
d.mkdir(exist_ok=True)
495495
m = d / "my_macro.sql"
496496
m.write_text(MACRO)
497-
return m
497+
return "my_macro"
498+
499+
500+
NON_ARG_MACRO = """
501+
{% macro one() %}
502+
1
503+
{% endmacro %}
504+
"""
505+
506+
507+
@pytest.fixture
508+
def non_arg_macro_name(dbt_project_dir):
509+
"""Create a dbt macro file."""
510+
d = dbt_project_dir / "macros"
511+
d.mkdir(exist_ok=True)
512+
m = d / "my_non_arg_macro.sql"
513+
m.write_text(NON_ARG_MACRO)
514+
return "one"
498515

499516

500517
@pytest.fixture

tests/hooks/dbt/test_dbt_hook_configs.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
RunTaskConfig,
2727
SeedTaskConfig,
2828
TestTaskConfig,
29-
parse_vars,
29+
parse_yaml_args,
3030
)
3131

3232

@@ -214,8 +214,8 @@ def test_build_task_minimal_config_singular(hook, profiles_file, dbt_project_fil
214214
),
215215
],
216216
)
217-
def test_parse_vars(vars, expected):
218-
result = parse_vars(vars)
217+
def test_parse_yaml_args(vars, expected):
218+
result = parse_yaml_args(vars)
219219
assert result == expected
220220

221221

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,28 @@
11
"""Unit test module for running dbt run-operation with the DbtHook."""
22

33

4-
def test_dbt_run_operation_task(hook, profiles_file, dbt_project_file, macro_file):
4+
def test_dbt_run_operation_task(hook, profiles_file, dbt_project_file, macro_name):
55
"""Test a dbt run-operation task."""
66
factory = hook.get_config_factory("run-operation")
77
config = factory.create_config(
88
project_dir=dbt_project_file.parent,
99
profiles_dir=profiles_file.parent,
10-
macro=str(macro_file.stem),
10+
macro=macro_name,
1111
args={"an_arg": 123},
1212
)
1313
success, results = hook.run_dbt_task(config)
1414
assert success is True
15+
16+
17+
def test_dbt_run_operation_task_with_no_args(
18+
hook, profiles_file, dbt_project_file, non_arg_macro_name
19+
):
20+
"""Test a dbt run-operation task."""
21+
factory = hook.get_config_factory("run-operation")
22+
config = factory.create_config(
23+
project_dir=dbt_project_file.parent,
24+
profiles_dir=profiles_file.parent,
25+
macro=non_arg_macro_name,
26+
)
27+
success, results = hook.run_dbt_task(config)
28+
assert success is True

tests/operators/test_dbt_run_operation.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def test_dbt_run_operation_mocked_all_args():
3838

3939

4040
def test_dbt_run_operation_non_existent_macro(
41-
profiles_file, dbt_project_file, macro_file
41+
profiles_file, dbt_project_file, macro_name
4242
):
4343
"""Test exectuion of DbtRunOperationOperator with a non-existent macro."""
4444
op = DbtRunOperationOperator(
@@ -53,33 +53,47 @@ def test_dbt_run_operation_non_existent_macro(
5353

5454

5555
def test_dbt_run_operation_missing_arguments(
56-
profiles_file, dbt_project_file, macro_file
56+
profiles_file, dbt_project_file, macro_name
5757
):
5858
"""Test exectuion of DbtRunOperationOperator with missing arguments."""
5959
op = DbtRunOperationOperator(
6060
task_id="dbt_task",
6161
project_dir=dbt_project_file.parent,
6262
profiles_dir=profiles_file.parent,
63-
macro=str(macro_file.stem),
63+
macro=macro_name,
6464
)
6565

6666
with pytest.raises(AirflowException):
6767
op.execute({})
6868

6969

70-
def test_dbt_run_operation_run_macro(profiles_file, dbt_project_file, macro_file):
70+
def test_dbt_run_operation_run_macro(profiles_file, dbt_project_file, macro_name):
7171
"""Test a dbt run-operation operator basic execution."""
7272
op = DbtRunOperationOperator(
7373
task_id="dbt_task",
7474
project_dir=dbt_project_file.parent,
7575
profiles_dir=profiles_file.parent,
76-
macro=str(macro_file.stem),
76+
macro=macro_name,
7777
args={"an_arg": 123},
7878
)
7979
execution_results = op.execute({})
8080
assert execution_results["success"] is True
8181

8282

83+
def test_dbt_run_operation_run_non_arg_macro(
84+
profiles_file, dbt_project_file, non_arg_macro_name
85+
):
86+
"""Test a dbt run-operation operator basic execution."""
87+
op = DbtRunOperationOperator(
88+
task_id="dbt_task",
89+
project_dir=dbt_project_file.parent,
90+
profiles_dir=profiles_file.parent,
91+
macro=non_arg_macro_name,
92+
)
93+
execution_results = op.execute({})
94+
assert execution_results["success"] is True
95+
96+
8397
BROKEN_MACRO1 = """
8498
{% macro my_broken_macro(an_arg) %}
8599
{% set sql %}

0 commit comments

Comments
 (0)