apache-airflow-providers-dbt-cloud 4.2.1__py3-none-any.whl → 4.3.1rc1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -29,7 +29,7 @@ from airflow import __version__ as airflow_version
29
29
 
30
30
  __all__ = ["__version__"]
31
31
 
32
- __version__ = "4.2.1"
32
+ __version__ = "4.3.1"
33
33
 
34
34
  if packaging.version.parse(packaging.version.parse(airflow_version).base_version) < packaging.version.parse(
35
35
  "2.9.0"
@@ -27,8 +27,9 @@ def get_provider_info():
27
27
  "name": "dbt Cloud",
28
28
  "description": "`dbt Cloud <https://www.getdbt.com/product/dbt-cloud/>`__\n",
29
29
  "state": "ready",
30
- "source-date-epoch": 1741508729,
30
+ "source-date-epoch": 1742980047,
31
31
  "versions": [
32
+ "4.3.1",
32
33
  "4.2.1",
33
34
  "4.2.0",
34
35
  "4.0.0",
@@ -24,7 +24,7 @@ from pathlib import Path
24
24
  from typing import TYPE_CHECKING, Any
25
25
 
26
26
  from airflow.configuration import conf
27
- from airflow.models import BaseOperator, XCom
27
+ from airflow.models import BaseOperator
28
28
  from airflow.providers.common.compat.version_compat import AIRFLOW_V_3_0_PLUS
29
29
  from airflow.providers.dbt.cloud.hooks.dbt import (
30
30
  DbtCloudHook,
@@ -41,7 +41,9 @@ if TYPE_CHECKING:
41
41
 
42
42
  if AIRFLOW_V_3_0_PLUS:
43
43
  from airflow.sdk import BaseOperatorLink
44
+ from airflow.sdk.execution_time.xcom import XCom
44
45
  else:
46
+ from airflow.models import XCom # type: ignore[no-redef]
45
47
  from airflow.models.baseoperatorlink import BaseOperatorLink # type: ignore[no-redef]
46
48
 
47
49
 
@@ -284,9 +286,13 @@ class DbtCloudRunJobOperator(BaseOperator):
284
286
  """
285
287
  from airflow.providers.openlineage.extractors import OperatorLineage
286
288
 
287
- if isinstance(self.run_id, int) and self.wait_for_termination is True:
288
- return generate_openlineage_events_from_dbt_cloud_run(operator=self, task_instance=task_instance)
289
- return OperatorLineage()
289
+ if not isinstance(self.run_id, int):
290
+ self.log.info("Skipping OpenLineage event extraction: `self.run_id` is not set.")
291
+ return OperatorLineage()
292
+ if not self.wait_for_termination:
293
+ self.log.info("Skipping OpenLineage event extraction: `self.wait_for_termination` is False.")
294
+ return OperatorLineage()
295
+ return generate_openlineage_events_from_dbt_cloud_run(operator=self, task_instance=task_instance)
290
296
 
291
297
 
292
298
  class DbtCloudGetJobRunArtifactOperator(BaseOperator):
@@ -17,39 +17,41 @@
17
17
  from __future__ import annotations
18
18
 
19
19
  import asyncio
20
+ import logging
20
21
  import re
21
- from contextlib import suppress
22
22
  from typing import TYPE_CHECKING
23
23
 
24
- from packaging.version import parse
25
-
26
- from airflow import __version__ as airflow_version
24
+ from airflow.providers.dbt.cloud.version_compat import AIRFLOW_V_2_10_PLUS, AIRFLOW_V_3_0_PLUS
27
25
 
28
26
  if TYPE_CHECKING:
29
- from packaging.version import Version
30
-
31
27
  from airflow.models.taskinstance import TaskInstance
32
28
  from airflow.providers.dbt.cloud.operators.dbt import DbtCloudRunJobOperator
33
29
  from airflow.providers.dbt.cloud.sensors.dbt import DbtCloudJobRunSensor
34
30
  from airflow.providers.openlineage.extractors.base import OperatorLineage
35
31
 
36
32
 
37
- _AIRFLOW_VERSION: Version = parse(parse(airflow_version).base_version)
33
+ log = logging.getLogger(__name__)
38
34
 
39
35
 
40
36
  def _get_logical_date(task_instance):
41
37
  # todo: remove when min airflow version >= 3.0
42
- if parse("3") > _AIRFLOW_VERSION:
43
- return task_instance.execution_date
44
- return task_instance.logical_date
38
+ if AIRFLOW_V_3_0_PLUS:
39
+ dagrun = task_instance.get_template_context()["dag_run"]
40
+ return dagrun.logical_date or dagrun.run_after
41
+
42
+ if hasattr(task_instance, "logical_date"):
43
+ date = task_instance.logical_date
44
+ else:
45
+ date = task_instance.execution_date
46
+
47
+ return date
45
48
 
46
49
 
47
50
  def _get_try_number(val):
48
51
  # todo: remove when min airflow version >= 2.10.0
49
- if parse("2.10.0") > _AIRFLOW_VERSION:
50
- return val.try_number - 1
51
- else:
52
+ if AIRFLOW_V_2_10_PLUS:
52
53
  return val.try_number
54
+ return val.try_number - 1
53
55
 
54
56
 
55
57
  def generate_openlineage_events_from_dbt_cloud_run(
@@ -87,6 +89,7 @@ def generate_openlineage_events_from_dbt_cloud_run(
87
89
  from airflow.providers.openlineage.plugins.listener import get_openlineage_listener
88
90
 
89
91
  # if no account_id set this will fallback
92
+ log.debug("Retrieving information about DBT job run.")
90
93
  job_run = operator.hook.get_job_run(
91
94
  run_id=operator.run_id, account_id=operator.account_id, include_related=["run_steps,job"]
92
95
  ).json()["data"]
@@ -98,6 +101,7 @@ def generate_openlineage_events_from_dbt_cloud_run(
98
101
  execute_steps = job["execute_steps"]
99
102
  run_steps = job_run["run_steps"]
100
103
 
104
+ log.debug("Filtering only DBT invocation steps for further processing.")
101
105
  # filter only dbt invocation steps
102
106
  steps = []
103
107
  for run_step in run_steps:
@@ -110,8 +114,15 @@ def generate_openlineage_events_from_dbt_cloud_run(
110
114
 
111
115
  # catalog is available only if docs are generated
112
116
  catalog = None
113
- with suppress(Exception):
117
+ try:
118
+ log.debug("Retrieving information about catalog artifact from DBT.")
114
119
  catalog = operator.hook.get_job_run_artifact(operator.run_id, path="catalog.json").json()["data"]
120
+ except Exception: # type: ignore
121
+ log.info(
122
+ "Openlineage could not find DBT catalog artifact, usually available when docs are generated."
123
+ "Proceeding with metadata extraction. "
124
+ "If you see error logs above about `HTTP error: Not Found` it's safe to ignore them."
125
+ )
115
126
 
116
127
  async def get_artifacts_for_steps(steps, artifacts):
117
128
  """Get artifacts for a list of steps concurrently."""
@@ -127,16 +138,37 @@ def generate_openlineage_events_from_dbt_cloud_run(
127
138
  return await asyncio.gather(*tasks)
128
139
 
129
140
  # get artifacts for steps concurrently
141
+ log.debug("Retrieving information about artifacts for all job steps from DBT.")
130
142
  step_artifacts = asyncio.run(
131
143
  get_artifacts_for_steps(steps=steps, artifacts=["manifest.json", "run_results.json"])
132
144
  )
133
145
 
146
+ log.debug("Preparing OpenLineage parent job information to be included in DBT events.")
147
+ # generate same run id of current task instance
148
+ parent_run_id = OpenLineageAdapter.build_task_instance_run_id(
149
+ dag_id=task_instance.dag_id,
150
+ task_id=operator.task_id,
151
+ logical_date=_get_logical_date(task_instance),
152
+ try_number=_get_try_number(task_instance),
153
+ map_index=task_instance.map_index,
154
+ )
155
+
156
+ parent_job = ParentRunMetadata(
157
+ run_id=parent_run_id,
158
+ job_name=f"{task_instance.dag_id}.{task_instance.task_id}",
159
+ job_namespace=namespace(),
160
+ )
161
+ client = get_openlineage_listener().adapter.get_or_create_openlineage_client()
162
+
134
163
  # process each step in loop, sending generated events in the same order as steps
135
- for artifacts in step_artifacts:
164
+ for counter, artifacts in enumerate(step_artifacts, 1):
165
+ log.debug("Parsing information about artifact no. %s.", counter)
166
+
136
167
  # process manifest
137
168
  manifest = artifacts["manifest.json"]
138
169
 
139
170
  if not artifacts.get("run_results.json", None):
171
+ log.debug("No run results found for artifact no. %s. Skipping.", counter)
140
172
  continue
141
173
 
142
174
  processor = DbtCloudArtifactProcessor(
@@ -150,26 +182,14 @@ def generate_openlineage_events_from_dbt_cloud_run(
150
182
  catalog=catalog,
151
183
  )
152
184
 
153
- # generate same run id of current task instance
154
- parent_run_id = OpenLineageAdapter.build_task_instance_run_id(
155
- dag_id=task_instance.dag_id,
156
- task_id=operator.task_id,
157
- logical_date=_get_logical_date(task_instance),
158
- try_number=_get_try_number(task_instance),
159
- map_index=task_instance.map_index,
160
- )
161
-
162
- parent_job = ParentRunMetadata(
163
- run_id=parent_run_id,
164
- job_name=f"{task_instance.dag_id}.{task_instance.task_id}",
165
- job_namespace=namespace(),
166
- )
167
185
  processor.dbt_run_metadata = parent_job
168
186
 
169
187
  events = processor.parse().events()
170
-
171
- client = get_openlineage_listener().adapter.get_or_create_openlineage_client()
188
+ log.debug("Found %s OpenLineage events for artifact no. %s.", len(events), counter)
172
189
 
173
190
  for event in events:
174
191
  client.emit(event=event)
192
+ log.debug("Emitted all OpenLineage events for artifact no. %s.", counter)
193
+
194
+ log.info("OpenLineage has successfully finished processing information about DBT job run.")
175
195
  return OperatorLineage()
@@ -0,0 +1,36 @@
1
+ # Licensed to the Apache Software Foundation (ASF) under one
2
+ # or more contributor license agreements. See the NOTICE file
3
+ # distributed with this work for additional information
4
+ # regarding copyright ownership. The ASF licenses this file
5
+ # to you under the Apache License, Version 2.0 (the
6
+ # "License"); you may not use this file except in compliance
7
+ # with the License. You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+ #
18
+ # NOTE! THIS FILE IS COPIED MANUALLY IN OTHER PROVIDERS DELIBERATELY TO AVOID ADDING UNNECESSARY
19
+ # DEPENDENCIES BETWEEN PROVIDERS. IF YOU WANT TO ADD CONDITIONAL CODE IN YOUR PROVIDER THAT DEPENDS
20
+ # ON AIRFLOW VERSION, PLEASE COPY THIS FILE TO THE ROOT PACKAGE OF YOUR PROVIDER AND IMPORT
21
+ # THOSE CONSTANTS FROM IT RATHER THAN IMPORTING THEM FROM ANOTHER PROVIDER OR TEST CODE
22
+ #
23
+ from __future__ import annotations
24
+
25
+
26
+ def get_base_airflow_version_tuple() -> tuple[int, int, int]:
27
+ from packaging.version import Version
28
+
29
+ from airflow import __version__
30
+
31
+ airflow_version = Version(__version__)
32
+ return airflow_version.major, airflow_version.minor, airflow_version.micro
33
+
34
+
35
+ AIRFLOW_V_2_10_PLUS = get_base_airflow_version_tuple() >= (2, 10, 0)
36
+ AIRFLOW_V_3_0_PLUS = get_base_airflow_version_tuple() >= (3, 0, 0)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: apache-airflow-providers-dbt-cloud
3
- Version: 4.2.1
3
+ Version: 4.3.1rc1
4
4
  Summary: Provider package apache-airflow-providers-dbt-cloud for Apache Airflow
5
5
  Keywords: airflow-provider,dbt.cloud,airflow,integration
6
6
  Author-email: Apache Software Foundation <dev@airflow.apache.org>
@@ -20,18 +20,18 @@ Classifier: Programming Language :: Python :: 3.10
20
20
  Classifier: Programming Language :: Python :: 3.11
21
21
  Classifier: Programming Language :: Python :: 3.12
22
22
  Classifier: Topic :: System :: Monitoring
23
- Requires-Dist: apache-airflow>=2.9.0
23
+ Requires-Dist: apache-airflow>=2.9.0rc0
24
24
  Requires-Dist: apache-airflow-providers-http
25
25
  Requires-Dist: asgiref>=2.3.0
26
26
  Requires-Dist: aiohttp>=3.9.2
27
27
  Requires-Dist: apache-airflow-providers-common-compat ; extra == "common-compat"
28
28
  Requires-Dist: apache-airflow-providers-openlineage>=1.7.0 ; extra == "openlineage"
29
29
  Project-URL: Bug Tracker, https://github.com/apache/airflow/issues
30
- Project-URL: Changelog, https://airflow.apache.org/docs/apache-airflow-providers-dbt-cloud/4.2.1/changelog.html
31
- Project-URL: Documentation, https://airflow.apache.org/docs/apache-airflow-providers-dbt-cloud/4.2.1
30
+ Project-URL: Changelog, https://airflow.apache.org/docs/apache-airflow-providers-dbt-cloud/4.3.1/changelog.html
31
+ Project-URL: Documentation, https://airflow.apache.org/docs/apache-airflow-providers-dbt-cloud/4.3.1
32
+ Project-URL: Mastodon, https://fosstodon.org/@airflow
32
33
  Project-URL: Slack Chat, https://s.apache.org/airflow-slack
33
34
  Project-URL: Source Code, https://github.com/apache/airflow
34
- Project-URL: Twitter, https://x.com/ApacheAirflow
35
35
  Project-URL: YouTube, https://www.youtube.com/channel/UCSXwxpWZQ7XZ1WL3wqevChA/
36
36
  Provides-Extra: common-compat
37
37
  Provides-Extra: openlineage
@@ -61,7 +61,7 @@ Provides-Extra: openlineage
61
61
 
62
62
  Package ``apache-airflow-providers-dbt-cloud``
63
63
 
64
- Release: ``4.2.1``
64
+ Release: ``4.3.1``
65
65
 
66
66
 
67
67
  `dbt Cloud <https://www.getdbt.com/product/dbt-cloud/>`__
@@ -74,7 +74,7 @@ This is a provider package for ``dbt.cloud`` provider. All classes for this prov
74
74
  are in ``airflow.providers.dbt.cloud`` python package.
75
75
 
76
76
  You can find package information and changelog for the provider
77
- in the `documentation <https://airflow.apache.org/docs/apache-airflow-providers-dbt-cloud/4.2.1/>`_.
77
+ in the `documentation <https://airflow.apache.org/docs/apache-airflow-providers-dbt-cloud/4.3.1/>`_.
78
78
 
79
79
  Installation
80
80
  ------------
@@ -101,7 +101,7 @@ Cross provider package dependencies
101
101
  -----------------------------------
102
102
 
103
103
  Those are dependencies that might be needed in order to use all the features of the package.
104
- You need to install the specified provider packages in order to use them.
104
+ You need to install the specified providers in order to use them.
105
105
 
106
106
  You can install such cross-provider dependencies when installing from PyPI. For example:
107
107
 
@@ -119,5 +119,5 @@ Dependent package
119
119
  ================================================================================================================== =================
120
120
 
121
121
  The changelog for the provider package can be found in the
122
- `changelog <https://airflow.apache.org/docs/apache-airflow-providers-dbt-cloud/4.2.1/changelog.html>`_.
122
+ `changelog <https://airflow.apache.org/docs/apache-airflow-providers-dbt-cloud/4.3.1/changelog.html>`_.
123
123
 
@@ -0,0 +1,18 @@
1
+ airflow/providers/dbt/cloud/LICENSE,sha256=gXPVwptPlW1TJ4HSuG5OMPg-a3h43OGMkZRR1rpwfJA,10850
2
+ airflow/providers/dbt/cloud/__init__.py,sha256=uuy3l3sjJZJG9-NzfvYGWd1ab5Olcmml4RTNn3DH3-Q,1496
3
+ airflow/providers/dbt/cloud/get_provider_info.py,sha256=lo5ZpzaiVezp6X0U2DqzGfTQBeM6XCiTOAsT-ArEgZg,3776
4
+ airflow/providers/dbt/cloud/version_compat.py,sha256=aHg90_DtgoSnQvILFICexMyNlHlALBdaeWqkX3dFDug,1605
5
+ airflow/providers/dbt/cloud/hooks/__init__.py,sha256=9hdXHABrVpkbpjZgUft39kOFL2xSGeG4GEua0Hmelus,785
6
+ airflow/providers/dbt/cloud/hooks/dbt.py,sha256=AxAEyeBewS0UQUtZMHLMbQmDAln3A_x3WdIrtzzK4Pk,34556
7
+ airflow/providers/dbt/cloud/operators/__init__.py,sha256=9hdXHABrVpkbpjZgUft39kOFL2xSGeG4GEua0Hmelus,785
8
+ airflow/providers/dbt/cloud/operators/dbt.py,sha256=dwagI9sMAXmzNRKRUsr7VvKaHJFdKNMj4iaz-Av8W3A,18043
9
+ airflow/providers/dbt/cloud/sensors/__init__.py,sha256=mlJxuZLkd5x-iq2SBwD3mvRQpt3YR7wjz_nceyF1IaI,787
10
+ airflow/providers/dbt/cloud/sensors/dbt.py,sha256=OGf-VNKcCNCrImrdE8PudmtDak_MKJfPhmaf7_ccOLg,5157
11
+ airflow/providers/dbt/cloud/triggers/__init__.py,sha256=9hdXHABrVpkbpjZgUft39kOFL2xSGeG4GEua0Hmelus,785
12
+ airflow/providers/dbt/cloud/triggers/dbt.py,sha256=Oabdc7FcNhCQxkjDC5SqAiYEw4hSZ9mQGZgSt36a1E0,4707
13
+ airflow/providers/dbt/cloud/utils/__init__.py,sha256=9hdXHABrVpkbpjZgUft39kOFL2xSGeG4GEua0Hmelus,785
14
+ airflow/providers/dbt/cloud/utils/openlineage.py,sha256=UueFNMgYw7E63uLZntnjzdEQ0V04vOO0M1YNBs5fF_c,7768
15
+ apache_airflow_providers_dbt_cloud-4.3.1rc1.dist-info/entry_points.txt,sha256=c18L1WEEK18WQeEGrm9kMVqutiYJHiWGH5jU1JqnToE,105
16
+ apache_airflow_providers_dbt_cloud-4.3.1rc1.dist-info/WHEEL,sha256=_2ozNFCLWc93bK4WKHCO-eDUENDlo-dgc9cU3qokYO4,82
17
+ apache_airflow_providers_dbt_cloud-4.3.1rc1.dist-info/METADATA,sha256=pxHD0xtWflLyRPXx2HcJZcycN1r-cIqKl8Z2mbsZ-lY,5695
18
+ apache_airflow_providers_dbt_cloud-4.3.1rc1.dist-info/RECORD,,
@@ -1,17 +0,0 @@
1
- airflow/providers/dbt/cloud/LICENSE,sha256=gXPVwptPlW1TJ4HSuG5OMPg-a3h43OGMkZRR1rpwfJA,10850
2
- airflow/providers/dbt/cloud/__init__.py,sha256=8bJh6-jVlHon3BqfhpuhOPvcwV1m6rsmzfooP3X2nLc,1496
3
- airflow/providers/dbt/cloud/get_provider_info.py,sha256=sdFwAL1GPiXWL40JiXqkJZQcgy3nhkl0IZaJJPWlanI,3755
4
- airflow/providers/dbt/cloud/hooks/__init__.py,sha256=9hdXHABrVpkbpjZgUft39kOFL2xSGeG4GEua0Hmelus,785
5
- airflow/providers/dbt/cloud/hooks/dbt.py,sha256=AxAEyeBewS0UQUtZMHLMbQmDAln3A_x3WdIrtzzK4Pk,34556
6
- airflow/providers/dbt/cloud/operators/__init__.py,sha256=9hdXHABrVpkbpjZgUft39kOFL2xSGeG4GEua0Hmelus,785
7
- airflow/providers/dbt/cloud/operators/dbt.py,sha256=mk5-z9r230EWWwDH06KtrjAUyZ5lIFe7qRT6RuhkSIA,17689
8
- airflow/providers/dbt/cloud/sensors/__init__.py,sha256=mlJxuZLkd5x-iq2SBwD3mvRQpt3YR7wjz_nceyF1IaI,787
9
- airflow/providers/dbt/cloud/sensors/dbt.py,sha256=OGf-VNKcCNCrImrdE8PudmtDak_MKJfPhmaf7_ccOLg,5157
10
- airflow/providers/dbt/cloud/triggers/__init__.py,sha256=9hdXHABrVpkbpjZgUft39kOFL2xSGeG4GEua0Hmelus,785
11
- airflow/providers/dbt/cloud/triggers/dbt.py,sha256=Oabdc7FcNhCQxkjDC5SqAiYEw4hSZ9mQGZgSt36a1E0,4707
12
- airflow/providers/dbt/cloud/utils/__init__.py,sha256=9hdXHABrVpkbpjZgUft39kOFL2xSGeG4GEua0Hmelus,785
13
- airflow/providers/dbt/cloud/utils/openlineage.py,sha256=6hGaRpfPE0HJSyEQNo4xt9Pfvdi9GI-mysIb4dBACpk,6611
14
- apache_airflow_providers_dbt_cloud-4.2.1.dist-info/entry_points.txt,sha256=c18L1WEEK18WQeEGrm9kMVqutiYJHiWGH5jU1JqnToE,105
15
- apache_airflow_providers_dbt_cloud-4.2.1.dist-info/WHEEL,sha256=_2ozNFCLWc93bK4WKHCO-eDUENDlo-dgc9cU3qokYO4,82
16
- apache_airflow_providers_dbt_cloud-4.2.1.dist-info/METADATA,sha256=FleQZDY3yK-UJI2XNqppNER_7WNsKbQm6aUkT1dh8Mw,5693
17
- apache_airflow_providers_dbt_cloud-4.2.1.dist-info/RECORD,,