airflow-dbt-python 1.0.4__tar.gz → 2.0.0__tar.gz
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.
- {airflow_dbt_python-1.0.4 → airflow_dbt_python-2.0.0}/PKG-INFO +20 -14
- {airflow_dbt_python-1.0.4 → airflow_dbt_python-2.0.0}/README.md +2 -2
- {airflow_dbt_python-1.0.4 → airflow_dbt_python-2.0.0}/airflow_dbt_python/__version__.py +1 -1
- {airflow_dbt_python-1.0.4 → airflow_dbt_python-2.0.0}/airflow_dbt_python/hooks/dbt.py +78 -42
- {airflow_dbt_python-1.0.4 → airflow_dbt_python-2.0.0}/airflow_dbt_python/hooks/git.py +15 -9
- {airflow_dbt_python-1.0.4 → airflow_dbt_python-2.0.0}/airflow_dbt_python/operators/dbt.py +23 -2
- {airflow_dbt_python-1.0.4 → airflow_dbt_python-2.0.0}/airflow_dbt_python/utils/configs.py +213 -46
- {airflow_dbt_python-1.0.4 → airflow_dbt_python-2.0.0}/airflow_dbt_python/utils/url.py +41 -2
- airflow_dbt_python-2.0.0/airflow_dbt_python/utils/version.py +30 -0
- {airflow_dbt_python-1.0.4 → airflow_dbt_python-2.0.0}/pyproject.toml +57 -20
- {airflow_dbt_python-1.0.4 → airflow_dbt_python-2.0.0}/setup.py +46 -16
- {airflow_dbt_python-1.0.4 → airflow_dbt_python-2.0.0}/LICENSE +0 -0
- {airflow_dbt_python-1.0.4 → airflow_dbt_python-2.0.0}/airflow_dbt_python/__init__.py +0 -0
- {airflow_dbt_python-1.0.4 → airflow_dbt_python-2.0.0}/airflow_dbt_python/hooks/__init__.py +0 -0
- {airflow_dbt_python-1.0.4 → airflow_dbt_python-2.0.0}/airflow_dbt_python/hooks/localfs.py +0 -0
- {airflow_dbt_python-1.0.4 → airflow_dbt_python-2.0.0}/airflow_dbt_python/hooks/remote.py +6 -6
- {airflow_dbt_python-1.0.4 → airflow_dbt_python-2.0.0}/airflow_dbt_python/hooks/s3.py +0 -0
- {airflow_dbt_python-1.0.4 → airflow_dbt_python-2.0.0}/airflow_dbt_python/operators/__init__.py +0 -0
- {airflow_dbt_python-1.0.4 → airflow_dbt_python-2.0.0}/airflow_dbt_python/utils/__init__.py +0 -0
- {airflow_dbt_python-1.0.4 → airflow_dbt_python-2.0.0}/airflow_dbt_python/utils/enums.py +0 -0
- {airflow_dbt_python-1.0.4 → airflow_dbt_python-2.0.0}/airflow_dbt_python/utils/env.py +0 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: airflow-dbt-python
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.0
|
|
4
4
|
Summary: A collection of Airflow operators, hooks, and utilities to execute dbt commands
|
|
5
5
|
Home-page: https://github.com/tomasfarias/airflow-dbt-python
|
|
6
6
|
License: MIT
|
|
7
7
|
Author: Tomás Farías Santana
|
|
8
8
|
Author-email: tomas@tomasfarias.dev
|
|
9
|
-
Requires-Python: >=3.
|
|
9
|
+
Requires-Python: >=3.8,<3.12
|
|
10
10
|
Classifier: Development Status :: 5 - Production/Stable
|
|
11
11
|
Classifier: Intended Audience :: Developers
|
|
12
12
|
Classifier: License :: OSI Approved :: MIT License
|
|
@@ -17,11 +17,9 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
17
17
|
Classifier: Programming Language :: Python :: 3.11
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.10
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
21
20
|
Classifier: Programming Language :: Python :: 3.8
|
|
22
21
|
Classifier: Programming Language :: Python :: 3.9
|
|
23
22
|
Provides-Extra: adapters
|
|
24
|
-
Provides-Extra: airflow
|
|
25
23
|
Provides-Extra: airflow-providers
|
|
26
24
|
Provides-Extra: bigquery
|
|
27
25
|
Provides-Extra: docs
|
|
@@ -31,16 +29,24 @@ Provides-Extra: redshift
|
|
|
31
29
|
Provides-Extra: s3
|
|
32
30
|
Provides-Extra: snowflake
|
|
33
31
|
Provides-Extra: spark
|
|
34
|
-
Requires-Dist: apache-airflow (>=2.
|
|
32
|
+
Requires-Dist: apache-airflow (>=2.2)
|
|
35
33
|
Requires-Dist: apache-airflow-providers-amazon (>=3.0.0) ; extra == "airflow-providers" or extra == "s3"
|
|
36
34
|
Requires-Dist: apache-airflow-providers-ssh (>=3.0.0) ; extra == "airflow-providers" or extra == "git"
|
|
37
|
-
Requires-Dist:
|
|
38
|
-
Requires-Dist:
|
|
39
|
-
Requires-Dist: dbt-
|
|
40
|
-
Requires-Dist: dbt-
|
|
41
|
-
Requires-Dist: dbt-
|
|
42
|
-
Requires-Dist: dbt-
|
|
43
|
-
Requires-Dist:
|
|
35
|
+
Requires-Dist: connexion (<3.0)
|
|
36
|
+
Requires-Dist: contextlib-chdir (==1.0.2) ; python_version < "3.11"
|
|
37
|
+
Requires-Dist: dbt-bigquery (>=1.4.0,<1.6.0) ; (python_version < "3.8") and (extra == "adapters" or extra == "bigquery")
|
|
38
|
+
Requires-Dist: dbt-bigquery (>=1.4.0,<1.8.0) ; (python_version >= "3.11") and (extra == "adapters" or extra == "bigquery")
|
|
39
|
+
Requires-Dist: dbt-core (>=1.4.0,<1.6.0) ; python_version < "3.8"
|
|
40
|
+
Requires-Dist: dbt-core (>=1.4.0,<1.8.0) ; python_version >= "3.11"
|
|
41
|
+
Requires-Dist: dbt-postgres (>=1.4.0,<1.6.0) ; (python_version < "3.8") and (extra == "adapters" or extra == "postgres")
|
|
42
|
+
Requires-Dist: dbt-postgres (>=1.4.0,<1.8.0) ; (python_version >= "3.11") and (extra == "adapters" or extra == "postgres")
|
|
43
|
+
Requires-Dist: dbt-redshift (>=1.4.0,<1.6.0) ; (python_version < "3.8") and (extra == "adapters" or extra == "redshift")
|
|
44
|
+
Requires-Dist: dbt-redshift (>=1.4.0,<1.8.0) ; (python_version >= "3.11") and (extra == "adapters" or extra == "redshift")
|
|
45
|
+
Requires-Dist: dbt-snowflake (>=1.4.0,<1.6.0) ; (python_version < "3.8") and (extra == "adapters" or extra == "snowflake")
|
|
46
|
+
Requires-Dist: dbt-snowflake (>=1.4.0,<1.8.0) ; (python_version >= "3.11") and (extra == "adapters" or extra == "snowflake")
|
|
47
|
+
Requires-Dist: dbt-spark (>=1.4.0,<1.6.0) ; (python_version < "3.8") and (extra == "adapters" or extra == "spark")
|
|
48
|
+
Requires-Dist: dbt-spark (>=1.4.0,<1.8.0) ; (python_version >= "3.11") and (extra == "adapters" or extra == "spark")
|
|
49
|
+
Requires-Dist: dulwich (>=0.21) ; extra == "git"
|
|
44
50
|
Project-URL: Repository, https://github.com/tomasfarias/airflow-dbt-python
|
|
45
51
|
Description-Content-Type: text/markdown
|
|
46
52
|
|
|
@@ -61,13 +67,13 @@ Read the [documentation](https://airflow-dbt-python.readthedocs.io) for examples
|
|
|
61
67
|
## Requirements
|
|
62
68
|
|
|
63
69
|
Before using *airflow-dbt-python*, ensure you meet the following requirements:
|
|
64
|
-
* A *dbt* project using [dbt-core](https://pypi.org/project/dbt-core/) version 1.
|
|
70
|
+
* A *dbt* project using [dbt-core](https://pypi.org/project/dbt-core/) version 1.4.0 or later.
|
|
65
71
|
* An Airflow environment using version 2.2 or later.
|
|
66
72
|
|
|
67
73
|
* If using any managed service, like AWS MWAA, ensure your environment is created with a supported version of Airflow.
|
|
68
74
|
* If self-hosting, Airflow installation instructions can be found in their [official documentation](https://airflow.apache.org/docs/apache-airflow/stable/installation/index.html).
|
|
69
75
|
|
|
70
|
-
* Running Python 3.
|
|
76
|
+
* Running Python 3.8 or later in your Airflow environment.
|
|
71
77
|
|
|
72
78
|
> **Warning**
|
|
73
79
|
>
|
|
@@ -15,13 +15,13 @@ Read the [documentation](https://airflow-dbt-python.readthedocs.io) for examples
|
|
|
15
15
|
## Requirements
|
|
16
16
|
|
|
17
17
|
Before using *airflow-dbt-python*, ensure you meet the following requirements:
|
|
18
|
-
* A *dbt* project using [dbt-core](https://pypi.org/project/dbt-core/) version 1.
|
|
18
|
+
* A *dbt* project using [dbt-core](https://pypi.org/project/dbt-core/) version 1.4.0 or later.
|
|
19
19
|
* An Airflow environment using version 2.2 or later.
|
|
20
20
|
|
|
21
21
|
* If using any managed service, like AWS MWAA, ensure your environment is created with a supported version of Airflow.
|
|
22
22
|
* If self-hosting, Airflow installation instructions can be found in their [official documentation](https://airflow.apache.org/docs/apache-airflow/stable/installation/index.html).
|
|
23
23
|
|
|
24
|
-
* Running Python 3.
|
|
24
|
+
* Running Python 3.8 or later in your Airflow environment.
|
|
25
25
|
|
|
26
26
|
> **Warning**
|
|
27
27
|
>
|
|
@@ -24,6 +24,14 @@ from airflow.exceptions import AirflowException
|
|
|
24
24
|
from airflow.hooks.base import BaseHook
|
|
25
25
|
from airflow.models.connection import Connection
|
|
26
26
|
|
|
27
|
+
from airflow_dbt_python.utils.version import DBT_INSTALLED_LESS_THAN_1_5
|
|
28
|
+
|
|
29
|
+
if sys.version_info >= (3, 11):
|
|
30
|
+
from contextlib import chdir as chdir_ctx
|
|
31
|
+
else:
|
|
32
|
+
from contextlib_chdir import chdir as chdir_ctx
|
|
33
|
+
|
|
34
|
+
|
|
27
35
|
if TYPE_CHECKING:
|
|
28
36
|
from dbt.contracts.results import RunResult
|
|
29
37
|
from dbt.task.base import BaseTask
|
|
@@ -208,6 +216,7 @@ class DbtHook(BaseHook):
|
|
|
208
216
|
replace_on_upload: bool = False,
|
|
209
217
|
artifacts: Optional[Iterable[str]] = None,
|
|
210
218
|
env_vars: Optional[Dict[str, Any]] = None,
|
|
219
|
+
write_perf_info: bool = False,
|
|
211
220
|
**kwargs,
|
|
212
221
|
) -> DbtTaskResult:
|
|
213
222
|
"""Run a dbt task with a given configuration and return the results.
|
|
@@ -219,9 +228,17 @@ class DbtHook(BaseHook):
|
|
|
219
228
|
of running the dbt command.
|
|
220
229
|
"""
|
|
221
230
|
from dbt.adapters.factory import register_adapter
|
|
222
|
-
from dbt.
|
|
223
|
-
from dbt.
|
|
224
|
-
from dbt.task.
|
|
231
|
+
from dbt.task.base import get_nearest_project_dir
|
|
232
|
+
from dbt.task.clean import CleanTask
|
|
233
|
+
from dbt.task.deps import DepsTask
|
|
234
|
+
|
|
235
|
+
from airflow_dbt_python.utils.version import DBT_INSTALLED_LESS_THAN_1_5
|
|
236
|
+
|
|
237
|
+
if DBT_INSTALLED_LESS_THAN_1_5:
|
|
238
|
+
from dbt.main import adapter_management, track_run # type: ignore
|
|
239
|
+
else:
|
|
240
|
+
from dbt.adapters.factory import adapter_management
|
|
241
|
+
from dbt.tracking import track_run
|
|
225
242
|
|
|
226
243
|
config = self.get_dbt_task_config(command, **kwargs)
|
|
227
244
|
extra_target = self.get_dbt_target_from_connection(config.target)
|
|
@@ -233,53 +250,62 @@ class DbtHook(BaseHook):
|
|
|
233
250
|
replace_on_upload=replace_on_upload,
|
|
234
251
|
env_vars=env_vars,
|
|
235
252
|
) as dbt_dir:
|
|
236
|
-
config.dbt_task.pre_init_hook(config)
|
|
237
|
-
self.ensure_profiles(config.profiles_dir)
|
|
238
|
-
|
|
239
|
-
task, runtime_config = config.create_dbt_task(extra_target)
|
|
240
|
-
|
|
241
253
|
# When creating tasks via from_args, dbt switches to the project directory.
|
|
242
254
|
# We have to do that here as we are not using from_args.
|
|
243
|
-
|
|
255
|
+
if DBT_INSTALLED_LESS_THAN_1_5:
|
|
256
|
+
# For compatibility with older versions of dbt, as the signature
|
|
257
|
+
# of move_to_nearest_project_dir changed in dbt-core 1.5 to take
|
|
258
|
+
# just the project_dir.
|
|
259
|
+
nearest_project_dir = get_nearest_project_dir(config) # type: ignore
|
|
260
|
+
else:
|
|
261
|
+
nearest_project_dir = get_nearest_project_dir(config.project_dir)
|
|
262
|
+
|
|
263
|
+
with chdir_ctx(nearest_project_dir):
|
|
264
|
+
config.dbt_task.pre_init_hook(config)
|
|
265
|
+
self.ensure_profiles(config)
|
|
244
266
|
|
|
245
|
-
|
|
267
|
+
task, runtime_config = config.create_dbt_task(
|
|
268
|
+
extra_target, write_perf_info
|
|
269
|
+
)
|
|
270
|
+
requires_profile = isinstance(task, (CleanTask, DepsTask))
|
|
246
271
|
|
|
247
|
-
|
|
248
|
-
|
|
272
|
+
self.setup_dbt_logging(task, config.debug)
|
|
273
|
+
|
|
274
|
+
if runtime_config is not None and not requires_profile:
|
|
249
275
|
# The deps command installs the dependencies, which means they may
|
|
250
276
|
# not exist before deps runs and the following would raise a
|
|
251
277
|
# CompilationError.
|
|
252
278
|
runtime_config.load_dependencies()
|
|
253
279
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
280
|
+
results = None
|
|
281
|
+
with adapter_management():
|
|
282
|
+
if not requires_profile:
|
|
283
|
+
if runtime_config is not None:
|
|
284
|
+
register_adapter(runtime_config)
|
|
259
285
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
286
|
+
with track_run(task):
|
|
287
|
+
results = task.run()
|
|
288
|
+
success = task.interpret_results(results)
|
|
263
289
|
|
|
264
|
-
|
|
265
|
-
|
|
290
|
+
if artifacts is None:
|
|
291
|
+
return DbtTaskResult(success, results, {})
|
|
266
292
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
293
|
+
saved_artifacts = {}
|
|
294
|
+
for artifact in artifacts:
|
|
295
|
+
artifact_path = Path(dbt_dir) / "target" / artifact
|
|
270
296
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
297
|
+
if not artifact_path.exists():
|
|
298
|
+
self.log.warning(
|
|
299
|
+
"Required dbt artifact %s was not found. "
|
|
300
|
+
"Perhaps dbt failed and couldn't generate it.",
|
|
301
|
+
artifact,
|
|
302
|
+
)
|
|
303
|
+
continue
|
|
278
304
|
|
|
279
|
-
|
|
280
|
-
|
|
305
|
+
with open(artifact_path) as artifact_file:
|
|
306
|
+
json_artifact = json.load(artifact_file)
|
|
281
307
|
|
|
282
|
-
|
|
308
|
+
saved_artifacts[artifact] = json_artifact
|
|
283
309
|
|
|
284
310
|
return DbtTaskResult(success, results, saved_artifacts)
|
|
285
311
|
|
|
@@ -373,7 +399,7 @@ class DbtHook(BaseHook):
|
|
|
373
399
|
if (project_dir_path / "profiles.yml").exists():
|
|
374
400
|
# We may have downloaded the profiles.yml file together
|
|
375
401
|
# with the project.
|
|
376
|
-
return
|
|
402
|
+
return new_project_dir, new_project_dir
|
|
377
403
|
|
|
378
404
|
if profiles_dir is not None:
|
|
379
405
|
profiles_file_path = self.download_dbt_profiles(
|
|
@@ -384,7 +410,7 @@ class DbtHook(BaseHook):
|
|
|
384
410
|
else:
|
|
385
411
|
new_profiles_dir = None
|
|
386
412
|
|
|
387
|
-
return
|
|
413
|
+
return new_project_dir, new_profiles_dir
|
|
388
414
|
|
|
389
415
|
def setup_dbt_logging(self, task: BaseTask, debug: Optional[bool]):
|
|
390
416
|
"""Setup dbt logging.
|
|
@@ -399,10 +425,18 @@ class DbtHook(BaseHook):
|
|
|
399
425
|
if task.config is not None:
|
|
400
426
|
log_path = getattr(task.config, "log_path", None)
|
|
401
427
|
|
|
402
|
-
|
|
428
|
+
if DBT_INSTALLED_LESS_THAN_1_5:
|
|
429
|
+
setup_event_logger(log_path or "logs")
|
|
430
|
+
else:
|
|
431
|
+
from dbt.flags import get_flags
|
|
432
|
+
|
|
433
|
+
flags = get_flags()
|
|
434
|
+
setup_event_logger(flags)
|
|
403
435
|
|
|
404
436
|
configured_file = logging.getLogger("configured_file")
|
|
405
437
|
file_log = logging.getLogger("file_log")
|
|
438
|
+
stdout_log = logging.getLogger("stdout_log")
|
|
439
|
+
stdout_log.propagate = True
|
|
406
440
|
|
|
407
441
|
if not debug:
|
|
408
442
|
# We have to do this after setting logs up as dbt hasn't
|
|
@@ -413,16 +447,18 @@ class DbtHook(BaseHook):
|
|
|
413
447
|
configured_file.setLevel("INFO")
|
|
414
448
|
configured_file.propagate = False
|
|
415
449
|
|
|
416
|
-
def ensure_profiles(self,
|
|
450
|
+
def ensure_profiles(self, config: BaseConfig):
|
|
417
451
|
"""Ensure a profiles file exists."""
|
|
418
|
-
if profiles_dir is not None:
|
|
419
|
-
# We expect one to exist given that we have
|
|
452
|
+
if config.profiles_dir is not None:
|
|
453
|
+
# We expect one to exist given that we have passed a profiles_dir.
|
|
420
454
|
return
|
|
421
455
|
|
|
422
456
|
profiles_path = Path.home() / ".dbt/profiles.yml"
|
|
457
|
+
config.profiles_dir = str(profiles_path.parent)
|
|
423
458
|
if not profiles_path.exists():
|
|
424
459
|
profiles_path.parent.mkdir(exist_ok=True)
|
|
425
|
-
profiles_path.
|
|
460
|
+
with profiles_path.open("w", encoding="utf-8") as f:
|
|
461
|
+
f.write("config:\n send_anonymous_usage_stats: false\n")
|
|
426
462
|
|
|
427
463
|
def get_dbt_target_from_connection(
|
|
428
464
|
self, target: Optional[str]
|
|
@@ -187,20 +187,26 @@ class DbtGitRemoteHook(SSHHook, DbtRemoteHook):
|
|
|
187
187
|
path = f"{url.netloc.split(':')[1]}/{str(url.path)}"
|
|
188
188
|
|
|
189
189
|
elif url.scheme in ("http", "https"):
|
|
190
|
-
|
|
191
|
-
netloc = parsedurl.hostname
|
|
190
|
+
base_url = url.hostname
|
|
192
191
|
|
|
193
|
-
if
|
|
194
|
-
|
|
195
|
-
if parsedurl.username:
|
|
196
|
-
netloc = "{}@{}".format(parsedurl.username, netloc)
|
|
192
|
+
if url.port:
|
|
193
|
+
base_url = f"{base_url}:{url.port}"
|
|
197
194
|
|
|
198
|
-
|
|
195
|
+
auth_params = {}
|
|
196
|
+
if url.authentication.username and url.authentication.password:
|
|
197
|
+
auth_params = {
|
|
198
|
+
"username": url.authentication.username,
|
|
199
|
+
"password": url.authentication.password,
|
|
200
|
+
}
|
|
201
|
+
base_url = f"{url.scheme}://{base_url}"
|
|
202
|
+
elif url.authentication.username:
|
|
203
|
+
base_url = f"{url.scheme}://{url.authentication.username}@{base_url}"
|
|
204
|
+
|
|
205
|
+
client = HttpGitClient(base_url, **auth_params)
|
|
199
206
|
|
|
200
|
-
client = HttpGitClient(url.netloc)
|
|
201
207
|
path = str(url.path)
|
|
202
208
|
|
|
203
209
|
else:
|
|
204
210
|
raise ValueError(f"Unsupported scheme: {url.scheme}")
|
|
205
211
|
|
|
206
|
-
return
|
|
212
|
+
return client, path
|
|
@@ -70,6 +70,9 @@ class DbtBaseOperator(BaseOperator):
|
|
|
70
70
|
warn_error: Optional[bool] = None,
|
|
71
71
|
# Logging
|
|
72
72
|
debug: Optional[bool] = None,
|
|
73
|
+
log_path: Optional[str] = None,
|
|
74
|
+
log_level: Optional[str] = None,
|
|
75
|
+
log_level_file: Optional[str] = None,
|
|
73
76
|
log_format: Optional[LogFormat] = None,
|
|
74
77
|
log_cache_events: Optional[bool] = False,
|
|
75
78
|
quiet: Optional[bool] = None,
|
|
@@ -80,12 +83,16 @@ class DbtBaseOperator(BaseOperator):
|
|
|
80
83
|
no_defer: Optional[bool] = None,
|
|
81
84
|
partial_parse: Optional[bool] = False,
|
|
82
85
|
no_partial_parse: Optional[bool] = None,
|
|
86
|
+
introspect: Optional[bool] = None,
|
|
87
|
+
no_introspect: Optional[bool] = None,
|
|
83
88
|
use_colors: Optional[bool] = None,
|
|
84
89
|
no_use_colors: Optional[bool] = None,
|
|
85
90
|
static_parser: Optional[bool] = None,
|
|
86
91
|
no_static_parser: Optional[bool] = None,
|
|
87
92
|
version_check: Optional[bool] = None,
|
|
88
93
|
no_version_check: Optional[bool] = None,
|
|
94
|
+
write_json: Optional[bool] = None,
|
|
95
|
+
write_perf_info: Optional[bool] = None,
|
|
89
96
|
anonymous_usage_stats: Optional[bool] = None,
|
|
90
97
|
no_anonymous_usage_stats: Optional[bool] = None,
|
|
91
98
|
# Extra features configuration
|
|
@@ -116,9 +123,12 @@ class DbtBaseOperator(BaseOperator):
|
|
|
116
123
|
self.warn_error = warn_error
|
|
117
124
|
|
|
118
125
|
self.debug = debug
|
|
126
|
+
self.log_path = log_path
|
|
119
127
|
self.log_cache_events = log_cache_events
|
|
120
128
|
self.quiet = quiet
|
|
121
129
|
self.no_print = no_print
|
|
130
|
+
self.log_level = log_level
|
|
131
|
+
self.log_level_file = log_level_file
|
|
122
132
|
self.log_format = log_format
|
|
123
133
|
self.record_timing_info = record_timing_info
|
|
124
134
|
|
|
@@ -137,9 +147,18 @@ class DbtBaseOperator(BaseOperator):
|
|
|
137
147
|
self.use_colors = use_colors
|
|
138
148
|
self.no_use_colors = no_use_colors
|
|
139
149
|
|
|
140
|
-
self.
|
|
150
|
+
self.introspect = introspect
|
|
151
|
+
self.no_introspect = no_introspect
|
|
152
|
+
|
|
153
|
+
self.version_check = version_check
|
|
141
154
|
self.no_version_check = no_version_check
|
|
142
155
|
|
|
156
|
+
self.write_json = write_json or (
|
|
157
|
+
do_xcom_push_artifacts and "run_results.json" in do_xcom_push_artifacts
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
self.write_perf_info = write_perf_info
|
|
161
|
+
|
|
143
162
|
self.dbt_conn_id = dbt_conn_id
|
|
144
163
|
self.profiles_conn_id = profiles_conn_id
|
|
145
164
|
self.project_conn_id = project_conn_id
|
|
@@ -174,7 +193,7 @@ class DbtBaseOperator(BaseOperator):
|
|
|
174
193
|
)
|
|
175
194
|
except Exception as e:
|
|
176
195
|
self.log.exception(
|
|
177
|
-
f"An error has
|
|
196
|
+
f"An error has occurred while executing dbt {self.command}", exc_info=e
|
|
178
197
|
)
|
|
179
198
|
raise AirflowException(
|
|
180
199
|
f"An error has occurred while executing dbt {self.command}"
|
|
@@ -428,11 +447,13 @@ class DbtCleanOperator(DbtBaseOperator):
|
|
|
428
447
|
self,
|
|
429
448
|
upload_dbt_project: bool = True,
|
|
430
449
|
delete_before_upload: bool = True,
|
|
450
|
+
clean_project_files_only: bool = True,
|
|
431
451
|
**kwargs,
|
|
432
452
|
) -> None:
|
|
433
453
|
super().__init__(**kwargs)
|
|
434
454
|
self.upload_dbt_project = upload_dbt_project
|
|
435
455
|
self.delete_before_upload = delete_before_upload
|
|
456
|
+
self.clean_project_files_only = clean_project_files_only
|
|
436
457
|
|
|
437
458
|
@property
|
|
438
459
|
def command(self) -> str:
|