This is an automated email from the ASF dual-hosted git repository.
shahar1 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new 26d3bbb6cfc Derive DbtCloudGetJobRunArtifactOperator default file name
after rendering (#70336)
26d3bbb6cfc is described below
commit 26d3bbb6cfc3a472e01f79e0c1da89bfe6dfe685
Author: Stefan Wang <[email protected]>
AuthorDate: Fri Jul 24 00:54:48 2026 -0700
Derive DbtCloudGetJobRunArtifactOperator default file name after rendering
(#70336)
* Derive DbtCloudGetJobRunArtifactOperator default file name after rendering
run_id, path and output_file_name are template fields, rendered after
__init__
runs. The constructor built the default output_file_name from self.run_id
and
self.path (the un-rendered Jinja expressions) and flattened slashes then.
With a
templated path, the '/'->'-' replacement ran on the expression, not the
resolved
path, so a rendered path like 'a/b/c.json' kept its slashes in the file
name.
Derive the default in execute(), after rendering.
related: #70296
---
.../airflow/providers/dbt/cloud/operators/dbt.py | 6 +++++-
.../tests/unit/dbt/cloud/operators/test_dbt.py | 21 +++++++++++++++++++++
.../ci/prek/validate_operators_init_exemptions.txt | 1 -
3 files changed, 26 insertions(+), 2 deletions(-)
diff --git
a/providers/dbt/cloud/src/airflow/providers/dbt/cloud/operators/dbt.py
b/providers/dbt/cloud/src/airflow/providers/dbt/cloud/operators/dbt.py
index 6547fadb0f9..b38d9a0f3cd 100644
--- a/providers/dbt/cloud/src/airflow/providers/dbt/cloud/operators/dbt.py
+++ b/providers/dbt/cloud/src/airflow/providers/dbt/cloud/operators/dbt.py
@@ -410,10 +410,14 @@ class DbtCloudGetJobRunArtifactOperator(BaseOperator):
self.path = path
self.account_id = account_id
self.step = step
- self.output_file_name = output_file_name or
f"{self.run_id}_{self.path}".replace("/", "-")
+ self.output_file_name = output_file_name
self.hook_params = hook_params or {}
def execute(self, context: Context) -> str:
+ # run_id/path are template fields; derive the default name after
rendering so it uses the
+ # resolved values, not the Jinja expressions.
+ if not self.output_file_name:
+ self.output_file_name = f"{self.run_id}_{self.path}".replace("/",
"-")
hook = DbtCloudHook(self.dbt_cloud_conn_id, **self.hook_params)
response = hook.get_job_run_artifact(
run_id=self.run_id, path=self.path, account_id=self.account_id,
step=self.step
diff --git a/providers/dbt/cloud/tests/unit/dbt/cloud/operators/test_dbt.py
b/providers/dbt/cloud/tests/unit/dbt/cloud/operators/test_dbt.py
index bb5988acdea..67d3fc33100 100644
--- a/providers/dbt/cloud/tests/unit/dbt/cloud/operators/test_dbt.py
+++ b/providers/dbt/cloud/tests/unit/dbt/cloud/operators/test_dbt.py
@@ -1058,6 +1058,27 @@ class TestDbtCloudGetJobRunArtifactOperator:
assert os.path.exists(tmp_path / operator.output_file_name)
assert return_value == operator.output_file_name
+
@patch("airflow.providers.dbt.cloud.hooks.dbt.DbtCloudHook.get_job_run_artifact")
+ def test_default_output_file_name_uses_rendered_path(self,
mock_get_artifact, tmp_path, monkeypatch):
+ # The default name flattens "/"->"-", so a templated path must resolve
before that.
+ operator = DbtCloudGetJobRunArtifactOperator(
+ task_id=TASK_ID,
+ dbt_cloud_conn_id=ACCOUNT_ID_CONN,
+ run_id=RUN_ID,
+ path="{{ params.p }}",
+ params={"p": "path/to/my/manifest.json"},
+ dag=self.dag,
+ )
+ operator.render_template_fields({"params": {"p":
"path/to/my/manifest.json"}})
+
+ mock_get_artifact.return_value.json.return_value = {"data": "file
contents"}
+ with monkeypatch.context() as ctx:
+ ctx.chdir(tmp_path)
+ return_value = operator.execute(context={})
+
+ assert operator.output_file_name ==
f"{RUN_ID}_path-to-my-manifest.json"
+ assert return_value == operator.output_file_name
+
@patch("airflow.providers.dbt.cloud.hooks.dbt.DbtCloudHook.get_job_run_artifact")
@pytest.mark.parametrize(
("conn_id", "account_id"),
diff --git a/scripts/ci/prek/validate_operators_init_exemptions.txt
b/scripts/ci/prek/validate_operators_init_exemptions.txt
index ebf6526cc10..c2e43f97a97 100644
--- a/scripts/ci/prek/validate_operators_init_exemptions.txt
+++ b/scripts/ci/prek/validate_operators_init_exemptions.txt
@@ -34,7 +34,6 @@
providers/databricks/src/airflow/providers/databricks/operators/databricks_repos
providers/databricks/src/airflow/providers/databricks/operators/databricks_repos.py::DatabricksReposUpdateOperator
providers/databricks/src/airflow/providers/databricks/operators/databricks_sql.py::DatabricksCopyIntoOperator
providers/databricks/src/airflow/providers/databricks/sensors/databricks.py::DatabricksSQLStatementsSensor
-providers/dbt/cloud/src/airflow/providers/dbt/cloud/operators/dbt.py::DbtCloudGetJobRunArtifactOperator
providers/docker/src/airflow/providers/docker/operators/docker.py::DockerOperator
providers/google/src/airflow/providers/google/cloud/operators/bigquery.py::BigQueryInsertJobOperator
providers/google/src/airflow/providers/google/cloud/operators/cloud_batch.py::CloudBatchSubmitJobOperator