dvt-core 0.52.2__cp310-cp310-macosx_10_9_x86_64.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.
Potentially problematic release.
This version of dvt-core might be problematic. Click here for more details.
- dbt/__init__.py +7 -0
- dbt/_pydantic_shim.py +26 -0
- dbt/artifacts/__init__.py +0 -0
- dbt/artifacts/exceptions/__init__.py +1 -0
- dbt/artifacts/exceptions/schemas.py +31 -0
- dbt/artifacts/resources/__init__.py +116 -0
- dbt/artifacts/resources/base.py +67 -0
- dbt/artifacts/resources/types.py +93 -0
- dbt/artifacts/resources/v1/analysis.py +10 -0
- dbt/artifacts/resources/v1/catalog.py +23 -0
- dbt/artifacts/resources/v1/components.py +274 -0
- dbt/artifacts/resources/v1/config.py +277 -0
- dbt/artifacts/resources/v1/documentation.py +11 -0
- dbt/artifacts/resources/v1/exposure.py +51 -0
- dbt/artifacts/resources/v1/function.py +52 -0
- dbt/artifacts/resources/v1/generic_test.py +31 -0
- dbt/artifacts/resources/v1/group.py +21 -0
- dbt/artifacts/resources/v1/hook.py +11 -0
- dbt/artifacts/resources/v1/macro.py +29 -0
- dbt/artifacts/resources/v1/metric.py +172 -0
- dbt/artifacts/resources/v1/model.py +145 -0
- dbt/artifacts/resources/v1/owner.py +10 -0
- dbt/artifacts/resources/v1/saved_query.py +111 -0
- dbt/artifacts/resources/v1/seed.py +41 -0
- dbt/artifacts/resources/v1/semantic_layer_components.py +72 -0
- dbt/artifacts/resources/v1/semantic_model.py +314 -0
- dbt/artifacts/resources/v1/singular_test.py +14 -0
- dbt/artifacts/resources/v1/snapshot.py +91 -0
- dbt/artifacts/resources/v1/source_definition.py +84 -0
- dbt/artifacts/resources/v1/sql_operation.py +10 -0
- dbt/artifacts/resources/v1/unit_test_definition.py +77 -0
- dbt/artifacts/schemas/__init__.py +0 -0
- dbt/artifacts/schemas/base.py +191 -0
- dbt/artifacts/schemas/batch_results.py +24 -0
- dbt/artifacts/schemas/catalog/__init__.py +11 -0
- dbt/artifacts/schemas/catalog/v1/__init__.py +0 -0
- dbt/artifacts/schemas/catalog/v1/catalog.py +59 -0
- dbt/artifacts/schemas/freshness/__init__.py +1 -0
- dbt/artifacts/schemas/freshness/v3/__init__.py +0 -0
- dbt/artifacts/schemas/freshness/v3/freshness.py +158 -0
- dbt/artifacts/schemas/manifest/__init__.py +2 -0
- dbt/artifacts/schemas/manifest/v12/__init__.py +0 -0
- dbt/artifacts/schemas/manifest/v12/manifest.py +211 -0
- dbt/artifacts/schemas/results.py +147 -0
- dbt/artifacts/schemas/run/__init__.py +2 -0
- dbt/artifacts/schemas/run/v5/__init__.py +0 -0
- dbt/artifacts/schemas/run/v5/run.py +184 -0
- dbt/artifacts/schemas/upgrades/__init__.py +4 -0
- dbt/artifacts/schemas/upgrades/upgrade_manifest.py +174 -0
- dbt/artifacts/schemas/upgrades/upgrade_manifest_dbt_version.py +2 -0
- dbt/artifacts/utils/validation.py +153 -0
- dbt/cli/__init__.py +1 -0
- dbt/cli/context.py +17 -0
- dbt/cli/exceptions.py +57 -0
- dbt/cli/flags.py +560 -0
- dbt/cli/main.py +2039 -0
- dbt/cli/option_types.py +121 -0
- dbt/cli/options.py +80 -0
- dbt/cli/params.py +804 -0
- dbt/cli/requires.py +490 -0
- dbt/cli/resolvers.py +50 -0
- dbt/cli/types.py +40 -0
- dbt/clients/__init__.py +0 -0
- dbt/clients/checked_load.py +83 -0
- dbt/clients/git.py +164 -0
- dbt/clients/jinja.py +206 -0
- dbt/clients/jinja_static.py +245 -0
- dbt/clients/registry.py +192 -0
- dbt/clients/yaml_helper.py +68 -0
- dbt/compilation.py +876 -0
- dbt/compute/__init__.py +14 -0
- dbt/compute/engines/__init__.py +12 -0
- dbt/compute/engines/spark_engine.py +624 -0
- dbt/compute/federated_executor.py +837 -0
- dbt/compute/filter_pushdown.cpython-310-darwin.so +0 -0
- dbt/compute/filter_pushdown.py +273 -0
- dbt/compute/jar_provisioning.cpython-310-darwin.so +0 -0
- dbt/compute/jar_provisioning.py +255 -0
- dbt/compute/java_compat.cpython-310-darwin.so +0 -0
- dbt/compute/java_compat.py +689 -0
- dbt/compute/jdbc_utils.cpython-310-darwin.so +0 -0
- dbt/compute/jdbc_utils.py +678 -0
- dbt/compute/smart_selector.cpython-310-darwin.so +0 -0
- dbt/compute/smart_selector.py +311 -0
- dbt/compute/strategies/__init__.py +54 -0
- dbt/compute/strategies/base.py +165 -0
- dbt/compute/strategies/dataproc.py +207 -0
- dbt/compute/strategies/emr.py +203 -0
- dbt/compute/strategies/local.py +364 -0
- dbt/compute/strategies/standalone.py +262 -0
- dbt/config/__init__.py +4 -0
- dbt/config/catalogs.py +94 -0
- dbt/config/compute.cpython-310-darwin.so +0 -0
- dbt/config/compute.py +547 -0
- dbt/config/dvt_profile.cpython-310-darwin.so +0 -0
- dbt/config/dvt_profile.py +342 -0
- dbt/config/profile.py +422 -0
- dbt/config/project.py +873 -0
- dbt/config/project_utils.py +28 -0
- dbt/config/renderer.py +231 -0
- dbt/config/runtime.py +553 -0
- dbt/config/selectors.py +208 -0
- dbt/config/utils.py +77 -0
- dbt/constants.py +28 -0
- dbt/context/__init__.py +0 -0
- dbt/context/base.py +745 -0
- dbt/context/configured.py +135 -0
- dbt/context/context_config.py +382 -0
- dbt/context/docs.py +82 -0
- dbt/context/exceptions_jinja.py +178 -0
- dbt/context/macro_resolver.py +195 -0
- dbt/context/macros.py +171 -0
- dbt/context/manifest.py +72 -0
- dbt/context/providers.py +2249 -0
- dbt/context/query_header.py +13 -0
- dbt/context/secret.py +58 -0
- dbt/context/target.py +74 -0
- dbt/contracts/__init__.py +0 -0
- dbt/contracts/files.py +413 -0
- dbt/contracts/graph/__init__.py +0 -0
- dbt/contracts/graph/manifest.py +1904 -0
- dbt/contracts/graph/metrics.py +97 -0
- dbt/contracts/graph/model_config.py +70 -0
- dbt/contracts/graph/node_args.py +42 -0
- dbt/contracts/graph/nodes.py +1806 -0
- dbt/contracts/graph/semantic_manifest.py +232 -0
- dbt/contracts/graph/unparsed.py +811 -0
- dbt/contracts/project.py +417 -0
- dbt/contracts/results.py +53 -0
- dbt/contracts/selection.py +23 -0
- dbt/contracts/sql.py +85 -0
- dbt/contracts/state.py +68 -0
- dbt/contracts/util.py +46 -0
- dbt/deprecations.py +346 -0
- dbt/deps/__init__.py +0 -0
- dbt/deps/base.py +152 -0
- dbt/deps/git.py +195 -0
- dbt/deps/local.py +79 -0
- dbt/deps/registry.py +130 -0
- dbt/deps/resolver.py +149 -0
- dbt/deps/tarball.py +120 -0
- dbt/docs/source/_ext/dbt_click.py +119 -0
- dbt/docs/source/conf.py +32 -0
- dbt/env_vars.py +64 -0
- dbt/event_time/event_time.py +40 -0
- dbt/event_time/sample_window.py +60 -0
- dbt/events/__init__.py +15 -0
- dbt/events/base_types.py +36 -0
- dbt/events/core_types_pb2.py +2 -0
- dbt/events/logging.py +108 -0
- dbt/events/types.py +2516 -0
- dbt/exceptions.py +1486 -0
- dbt/flags.py +89 -0
- dbt/graph/__init__.py +11 -0
- dbt/graph/cli.py +247 -0
- dbt/graph/graph.py +172 -0
- dbt/graph/queue.py +214 -0
- dbt/graph/selector.py +374 -0
- dbt/graph/selector_methods.py +975 -0
- dbt/graph/selector_spec.py +222 -0
- dbt/graph/thread_pool.py +18 -0
- dbt/hooks.py +21 -0
- dbt/include/README.md +49 -0
- dbt/include/__init__.py +3 -0
- dbt/include/starter_project/.gitignore +4 -0
- dbt/include/starter_project/README.md +15 -0
- dbt/include/starter_project/__init__.py +3 -0
- dbt/include/starter_project/analyses/.gitkeep +0 -0
- dbt/include/starter_project/dbt_project.yml +36 -0
- dbt/include/starter_project/macros/.gitkeep +0 -0
- dbt/include/starter_project/models/example/my_first_dbt_model.sql +27 -0
- dbt/include/starter_project/models/example/my_second_dbt_model.sql +6 -0
- dbt/include/starter_project/models/example/schema.yml +21 -0
- dbt/include/starter_project/seeds/.gitkeep +0 -0
- dbt/include/starter_project/snapshots/.gitkeep +0 -0
- dbt/include/starter_project/tests/.gitkeep +0 -0
- dbt/internal_deprecations.py +26 -0
- dbt/jsonschemas/__init__.py +3 -0
- dbt/jsonschemas/jsonschemas.py +309 -0
- dbt/jsonschemas/project/0.0.110.json +4717 -0
- dbt/jsonschemas/project/0.0.85.json +2015 -0
- dbt/jsonschemas/resources/0.0.110.json +2636 -0
- dbt/jsonschemas/resources/0.0.85.json +2536 -0
- dbt/jsonschemas/resources/latest.json +6773 -0
- dbt/links.py +4 -0
- dbt/materializations/__init__.py +0 -0
- dbt/materializations/incremental/__init__.py +0 -0
- dbt/materializations/incremental/microbatch.py +236 -0
- dbt/mp_context.py +8 -0
- dbt/node_types.py +37 -0
- dbt/parser/__init__.py +23 -0
- dbt/parser/analysis.py +21 -0
- dbt/parser/base.py +548 -0
- dbt/parser/common.py +266 -0
- dbt/parser/docs.py +52 -0
- dbt/parser/fixtures.py +51 -0
- dbt/parser/functions.py +30 -0
- dbt/parser/generic_test.py +100 -0
- dbt/parser/generic_test_builders.py +333 -0
- dbt/parser/hooks.py +118 -0
- dbt/parser/macros.py +137 -0
- dbt/parser/manifest.py +2204 -0
- dbt/parser/models.py +573 -0
- dbt/parser/partial.py +1178 -0
- dbt/parser/read_files.py +445 -0
- dbt/parser/schema_generic_tests.py +422 -0
- dbt/parser/schema_renderer.py +111 -0
- dbt/parser/schema_yaml_readers.py +935 -0
- dbt/parser/schemas.py +1466 -0
- dbt/parser/search.py +149 -0
- dbt/parser/seeds.py +28 -0
- dbt/parser/singular_test.py +20 -0
- dbt/parser/snapshots.py +44 -0
- dbt/parser/sources.py +558 -0
- dbt/parser/sql.py +62 -0
- dbt/parser/unit_tests.py +621 -0
- dbt/plugins/__init__.py +20 -0
- dbt/plugins/contracts.py +9 -0
- dbt/plugins/exceptions.py +2 -0
- dbt/plugins/manager.py +163 -0
- dbt/plugins/manifest.py +21 -0
- dbt/profiler.py +20 -0
- dbt/py.typed +1 -0
- dbt/query_analyzer.cpython-310-darwin.so +0 -0
- dbt/query_analyzer.py +410 -0
- dbt/runners/__init__.py +2 -0
- dbt/runners/exposure_runner.py +7 -0
- dbt/runners/no_op_runner.py +45 -0
- dbt/runners/saved_query_runner.py +7 -0
- dbt/selected_resources.py +8 -0
- dbt/task/__init__.py +0 -0
- dbt/task/base.py +503 -0
- dbt/task/build.py +197 -0
- dbt/task/clean.py +56 -0
- dbt/task/clone.py +161 -0
- dbt/task/compile.py +150 -0
- dbt/task/compute.py +454 -0
- dbt/task/debug.py +505 -0
- dbt/task/deps.py +280 -0
- dbt/task/docs/__init__.py +3 -0
- dbt/task/docs/generate.py +660 -0
- dbt/task/docs/index.html +250 -0
- dbt/task/docs/serve.py +29 -0
- dbt/task/freshness.py +322 -0
- dbt/task/function.py +121 -0
- dbt/task/group_lookup.py +46 -0
- dbt/task/init.py +553 -0
- dbt/task/java.py +316 -0
- dbt/task/list.py +236 -0
- dbt/task/printer.py +175 -0
- dbt/task/retry.py +175 -0
- dbt/task/run.py +1306 -0
- dbt/task/run_operation.py +141 -0
- dbt/task/runnable.py +758 -0
- dbt/task/seed.py +103 -0
- dbt/task/show.py +149 -0
- dbt/task/snapshot.py +56 -0
- dbt/task/spark.py +414 -0
- dbt/task/sql.py +110 -0
- dbt/task/target_sync.py +759 -0
- dbt/task/test.py +464 -0
- dbt/tests/fixtures/__init__.py +1 -0
- dbt/tests/fixtures/project.py +620 -0
- dbt/tests/util.py +651 -0
- dbt/tracking.py +529 -0
- dbt/utils/__init__.py +3 -0
- dbt/utils/artifact_upload.py +151 -0
- dbt/utils/utils.py +408 -0
- dbt/version.py +268 -0
- dvt_cli/__init__.py +72 -0
- dvt_core-0.52.2.dist-info/METADATA +286 -0
- dvt_core-0.52.2.dist-info/RECORD +275 -0
- dvt_core-0.52.2.dist-info/WHEEL +5 -0
- dvt_core-0.52.2.dist-info/entry_points.txt +2 -0
- dvt_core-0.52.2.dist-info/top_level.txt +2 -0
dbt/task/__init__.py
ADDED
|
File without changes
|
dbt/task/base.py
ADDED
|
@@ -0,0 +1,503 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import threading
|
|
3
|
+
import time
|
|
4
|
+
import traceback
|
|
5
|
+
from abc import ABCMeta, abstractmethod
|
|
6
|
+
from contextlib import nullcontext
|
|
7
|
+
from datetime import datetime, timezone
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Any, Dict, List, Optional, Set
|
|
10
|
+
|
|
11
|
+
import dbt.exceptions
|
|
12
|
+
import dbt_common.exceptions.base
|
|
13
|
+
from dbt import tracking
|
|
14
|
+
from dbt.artifacts.resources.types import NodeType
|
|
15
|
+
from dbt.artifacts.schemas.results import (
|
|
16
|
+
NodeStatus,
|
|
17
|
+
RunningStatus,
|
|
18
|
+
RunStatus,
|
|
19
|
+
TimingInfo,
|
|
20
|
+
collect_timing_info,
|
|
21
|
+
)
|
|
22
|
+
from dbt.artifacts.schemas.run import RunResult
|
|
23
|
+
from dbt.cli.flags import Flags
|
|
24
|
+
from dbt.compilation import Compiler
|
|
25
|
+
from dbt.config import RuntimeConfig
|
|
26
|
+
from dbt.config.profile import read_profile
|
|
27
|
+
from dbt.constants import DBT_PROJECT_FILE_NAME
|
|
28
|
+
from dbt.contracts.graph.manifest import Manifest
|
|
29
|
+
from dbt.events.types import (
|
|
30
|
+
CatchableExceptionOnRun,
|
|
31
|
+
GenericExceptionOnRun,
|
|
32
|
+
InternalErrorOnRun,
|
|
33
|
+
LogDbtProfileError,
|
|
34
|
+
LogDbtProjectError,
|
|
35
|
+
LogDebugStackTrace,
|
|
36
|
+
LogSkipBecauseError,
|
|
37
|
+
NodeCompiling,
|
|
38
|
+
NodeConnectionReleaseError,
|
|
39
|
+
NodeExecuting,
|
|
40
|
+
SkippingDetails,
|
|
41
|
+
)
|
|
42
|
+
from dbt.flags import get_flags
|
|
43
|
+
from dbt.graph import Graph
|
|
44
|
+
from dbt.task import group_lookup
|
|
45
|
+
from dbt.task.printer import print_run_result_error
|
|
46
|
+
from dbt_common.events.contextvars import get_node_info
|
|
47
|
+
from dbt_common.events.functions import fire_event
|
|
48
|
+
from dbt_common.exceptions import DbtInternalError, DbtRuntimeError, NotImplementedError
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def read_profiles(profiles_dir: Optional[str] = None) -> Dict[str, Any]:
|
|
52
|
+
"""This is only used for some error handling"""
|
|
53
|
+
if profiles_dir is None:
|
|
54
|
+
profiles_dir = get_flags().PROFILES_DIR
|
|
55
|
+
|
|
56
|
+
raw_profiles = read_profile(profiles_dir)
|
|
57
|
+
|
|
58
|
+
if raw_profiles is None:
|
|
59
|
+
profiles = {}
|
|
60
|
+
else:
|
|
61
|
+
profiles = {k: v for (k, v) in raw_profiles.items() if k != "config"}
|
|
62
|
+
|
|
63
|
+
return profiles
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class BaseTask(metaclass=ABCMeta):
|
|
67
|
+
def __init__(self, args: Flags) -> None:
|
|
68
|
+
self.args = args
|
|
69
|
+
|
|
70
|
+
def __enter__(self):
|
|
71
|
+
self.orig_dir = os.getcwd()
|
|
72
|
+
return self
|
|
73
|
+
|
|
74
|
+
def __exit__(self, exc_type, exc_value, traceback):
|
|
75
|
+
os.chdir(self.orig_dir)
|
|
76
|
+
|
|
77
|
+
@abstractmethod
|
|
78
|
+
def run(self):
|
|
79
|
+
raise dbt_common.exceptions.base.NotImplementedError("Not Implemented")
|
|
80
|
+
|
|
81
|
+
def interpret_results(self, results):
|
|
82
|
+
return True
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def get_nearest_project_dir(project_dir: Optional[str]) -> Path:
|
|
86
|
+
# If the user provides an explicit project directory, use that
|
|
87
|
+
# but don't look at parent directories.
|
|
88
|
+
if project_dir:
|
|
89
|
+
cur_dir = Path(project_dir)
|
|
90
|
+
project_file = Path(project_dir) / DBT_PROJECT_FILE_NAME
|
|
91
|
+
if project_file.is_file():
|
|
92
|
+
return cur_dir
|
|
93
|
+
else:
|
|
94
|
+
raise dbt_common.exceptions.DbtRuntimeError(
|
|
95
|
+
"fatal: Invalid --project-dir flag. Not a dbt project. "
|
|
96
|
+
"Missing dbt_project.yml file"
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
cur_dir = Path.cwd()
|
|
100
|
+
project_file = cur_dir / DBT_PROJECT_FILE_NAME
|
|
101
|
+
if project_file.is_file():
|
|
102
|
+
return cur_dir
|
|
103
|
+
else:
|
|
104
|
+
raise dbt_common.exceptions.DbtRuntimeError(
|
|
105
|
+
"fatal: Not a dbt project (or any of the parent directories). "
|
|
106
|
+
"Missing dbt_project.yml file"
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def move_to_nearest_project_dir(project_dir: Optional[str]) -> Path:
|
|
111
|
+
nearest_project_dir = get_nearest_project_dir(project_dir)
|
|
112
|
+
os.chdir(nearest_project_dir)
|
|
113
|
+
return nearest_project_dir
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
# TODO: look into deprecating this class in favor of several small functions that
|
|
117
|
+
# produce the same behavior. currently this class only contains manifest compilation,
|
|
118
|
+
# holding a manifest, and moving direcories.
|
|
119
|
+
class ConfiguredTask(BaseTask):
|
|
120
|
+
def __init__(
|
|
121
|
+
self, args: Flags, config: RuntimeConfig, manifest: Optional[Manifest] = None
|
|
122
|
+
) -> None:
|
|
123
|
+
super().__init__(args)
|
|
124
|
+
self.config = config
|
|
125
|
+
self.graph: Optional[Graph] = None
|
|
126
|
+
self.manifest = manifest
|
|
127
|
+
self.compiler = Compiler(self.config)
|
|
128
|
+
|
|
129
|
+
def compile_manifest(self) -> None:
|
|
130
|
+
if self.manifest is None:
|
|
131
|
+
raise DbtInternalError("compile_manifest called before manifest was loaded")
|
|
132
|
+
|
|
133
|
+
start_compile_manifest = time.perf_counter()
|
|
134
|
+
|
|
135
|
+
self.graph = self.compiler.compile(self.manifest)
|
|
136
|
+
|
|
137
|
+
compile_time = time.perf_counter() - start_compile_manifest
|
|
138
|
+
if dbt.tracking.active_user is not None:
|
|
139
|
+
dbt.tracking.track_runnable_timing({"graph_compilation_elapsed": compile_time})
|
|
140
|
+
|
|
141
|
+
@classmethod
|
|
142
|
+
def from_args(cls, args: Flags, *pargs, **kwargs):
|
|
143
|
+
move_to_nearest_project_dir(args.project_dir)
|
|
144
|
+
try:
|
|
145
|
+
# This is usually RuntimeConfig
|
|
146
|
+
config = RuntimeConfig.from_args(args)
|
|
147
|
+
except dbt.exceptions.DbtProjectError as exc:
|
|
148
|
+
fire_event(LogDbtProjectError(exc=str(exc)))
|
|
149
|
+
|
|
150
|
+
tracking.track_invalid_invocation(args=args, result_type=exc.result_type)
|
|
151
|
+
raise dbt_common.exceptions.DbtRuntimeError("Could not run dbt") from exc
|
|
152
|
+
except dbt.exceptions.DbtProfileError as exc:
|
|
153
|
+
all_profile_names = list(read_profiles(get_flags().PROFILES_DIR).keys())
|
|
154
|
+
fire_event(LogDbtProfileError(exc=str(exc), profiles=all_profile_names))
|
|
155
|
+
tracking.track_invalid_invocation(args=args, result_type=exc.result_type)
|
|
156
|
+
raise dbt_common.exceptions.DbtRuntimeError("Could not run dbt") from exc
|
|
157
|
+
return cls(args, config, *pargs, **kwargs)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
class ExecutionContext:
|
|
161
|
+
"""During execution and error handling, dbt makes use of mutable state:
|
|
162
|
+
timing information and the newest (compiled vs executed) form of the node.
|
|
163
|
+
"""
|
|
164
|
+
|
|
165
|
+
def __init__(self, node) -> None:
|
|
166
|
+
self.timing: List[TimingInfo] = []
|
|
167
|
+
self.node = node
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
class BaseRunner(metaclass=ABCMeta):
|
|
171
|
+
def __init__(self, config, adapter, node, node_index: int, num_nodes: int) -> None:
|
|
172
|
+
self.config = config
|
|
173
|
+
self.compiler = Compiler(config)
|
|
174
|
+
self.adapter = adapter
|
|
175
|
+
self.node = node
|
|
176
|
+
self.node_index = node_index
|
|
177
|
+
self.num_nodes = num_nodes
|
|
178
|
+
|
|
179
|
+
self.skip = False
|
|
180
|
+
self.skip_cause: Optional[RunResult] = None
|
|
181
|
+
|
|
182
|
+
self.run_ephemeral_models = False
|
|
183
|
+
|
|
184
|
+
@abstractmethod
|
|
185
|
+
def compile(self, manifest: Manifest) -> Any:
|
|
186
|
+
pass
|
|
187
|
+
|
|
188
|
+
def _node_build_path(self) -> Optional[str]:
|
|
189
|
+
return self.node.build_path if hasattr(self.node, "build_path") else None
|
|
190
|
+
|
|
191
|
+
def get_result_status(self, result) -> Dict[str, str]:
|
|
192
|
+
if result.status == NodeStatus.Error:
|
|
193
|
+
return {"node_status": "error", "node_error": str(result.message)}
|
|
194
|
+
elif result.status == NodeStatus.Skipped:
|
|
195
|
+
return {"node_status": "skipped"}
|
|
196
|
+
elif result.status == NodeStatus.Fail:
|
|
197
|
+
return {"node_status": "failed"}
|
|
198
|
+
elif result.status == NodeStatus.Warn:
|
|
199
|
+
return {"node_status": "warn"}
|
|
200
|
+
else:
|
|
201
|
+
return {"node_status": "passed"}
|
|
202
|
+
|
|
203
|
+
def run_with_hooks(self, manifest):
|
|
204
|
+
if self.skip:
|
|
205
|
+
return self.on_skip()
|
|
206
|
+
|
|
207
|
+
# no before/after printing for ephemeral mdoels
|
|
208
|
+
if not self.node.is_ephemeral_model:
|
|
209
|
+
self.before_execute()
|
|
210
|
+
|
|
211
|
+
result = self.safe_run(manifest)
|
|
212
|
+
self.node.update_event_status(
|
|
213
|
+
node_status=result.status,
|
|
214
|
+
finished_at=datetime.now(timezone.utc).replace(tzinfo=None).isoformat(),
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
if not self.node.is_ephemeral_model:
|
|
218
|
+
self.after_execute(result)
|
|
219
|
+
|
|
220
|
+
return result
|
|
221
|
+
|
|
222
|
+
def _build_run_result(
|
|
223
|
+
self,
|
|
224
|
+
node,
|
|
225
|
+
start_time,
|
|
226
|
+
status,
|
|
227
|
+
timing_info,
|
|
228
|
+
message,
|
|
229
|
+
agate_table=None,
|
|
230
|
+
adapter_response=None,
|
|
231
|
+
failures=None,
|
|
232
|
+
batch_results=None,
|
|
233
|
+
):
|
|
234
|
+
execution_time = time.time() - start_time
|
|
235
|
+
thread_id = threading.current_thread().name
|
|
236
|
+
if adapter_response is None:
|
|
237
|
+
adapter_response = {}
|
|
238
|
+
return RunResult(
|
|
239
|
+
status=status,
|
|
240
|
+
thread_id=thread_id,
|
|
241
|
+
execution_time=execution_time,
|
|
242
|
+
timing=timing_info,
|
|
243
|
+
message=message,
|
|
244
|
+
node=node,
|
|
245
|
+
agate_table=agate_table,
|
|
246
|
+
adapter_response=adapter_response,
|
|
247
|
+
failures=failures,
|
|
248
|
+
batch_results=batch_results,
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
def error_result(self, node, message, start_time, timing_info):
|
|
252
|
+
return self._build_run_result(
|
|
253
|
+
node=node,
|
|
254
|
+
start_time=start_time,
|
|
255
|
+
status=RunStatus.Error,
|
|
256
|
+
timing_info=timing_info,
|
|
257
|
+
message=message,
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
def ephemeral_result(self, node, start_time, timing_info):
|
|
261
|
+
return self._build_run_result(
|
|
262
|
+
node=node,
|
|
263
|
+
start_time=start_time,
|
|
264
|
+
status=RunStatus.Success,
|
|
265
|
+
timing_info=timing_info,
|
|
266
|
+
message=None,
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
def from_run_result(self, result, start_time, timing_info):
|
|
270
|
+
return self._build_run_result(
|
|
271
|
+
node=result.node,
|
|
272
|
+
start_time=start_time,
|
|
273
|
+
status=result.status,
|
|
274
|
+
timing_info=timing_info,
|
|
275
|
+
message=result.message,
|
|
276
|
+
agate_table=result.agate_table,
|
|
277
|
+
adapter_response=result.adapter_response,
|
|
278
|
+
failures=result.failures,
|
|
279
|
+
batch_results=result.batch_results,
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
def compile_and_execute(self, manifest: Manifest, ctx: ExecutionContext):
|
|
283
|
+
result = None
|
|
284
|
+
with (
|
|
285
|
+
self.adapter.connection_named(self.node.unique_id, self.node)
|
|
286
|
+
if get_flags().INTROSPECT
|
|
287
|
+
else nullcontext()
|
|
288
|
+
):
|
|
289
|
+
ctx.node.update_event_status(node_status=RunningStatus.Compiling)
|
|
290
|
+
fire_event(
|
|
291
|
+
NodeCompiling(
|
|
292
|
+
node_info=ctx.node.node_info,
|
|
293
|
+
)
|
|
294
|
+
)
|
|
295
|
+
with collect_timing_info("compile", ctx.timing.append):
|
|
296
|
+
# if we fail here, we still have a compiled node to return
|
|
297
|
+
# this has the benefit of showing a build path for the errant
|
|
298
|
+
# model. This calls the 'compile' method in CompileTask
|
|
299
|
+
ctx.node = self.compile(manifest)
|
|
300
|
+
|
|
301
|
+
# for ephemeral nodes, we only want to compile, not run
|
|
302
|
+
if not ctx.node.is_ephemeral_model or self.run_ephemeral_models:
|
|
303
|
+
ctx.node.update_event_status(node_status=RunningStatus.Executing)
|
|
304
|
+
fire_event(
|
|
305
|
+
NodeExecuting(
|
|
306
|
+
node_info=ctx.node.node_info,
|
|
307
|
+
)
|
|
308
|
+
)
|
|
309
|
+
with collect_timing_info("execute", ctx.timing.append):
|
|
310
|
+
result = self.run(ctx.node, manifest)
|
|
311
|
+
ctx.node = result.node
|
|
312
|
+
|
|
313
|
+
return result
|
|
314
|
+
|
|
315
|
+
def _handle_catchable_exception(self, e: DbtRuntimeError, ctx: ExecutionContext) -> str:
|
|
316
|
+
if e.node is None:
|
|
317
|
+
e.add_node(ctx.node)
|
|
318
|
+
|
|
319
|
+
fire_event(
|
|
320
|
+
CatchableExceptionOnRun(
|
|
321
|
+
exc=str(e), exc_info=traceback.format_exc(), node_info=get_node_info()
|
|
322
|
+
)
|
|
323
|
+
)
|
|
324
|
+
return str(e)
|
|
325
|
+
|
|
326
|
+
def _handle_internal_exception(self, e: DbtInternalError, ctx: ExecutionContext) -> str:
|
|
327
|
+
fire_event(
|
|
328
|
+
InternalErrorOnRun(
|
|
329
|
+
build_path=self._node_build_path(), exc=str(e), node_info=get_node_info()
|
|
330
|
+
)
|
|
331
|
+
)
|
|
332
|
+
return str(e)
|
|
333
|
+
|
|
334
|
+
def _handle_generic_exception(self, e: Exception, ctx: ExecutionContext) -> str:
|
|
335
|
+
fire_event(
|
|
336
|
+
GenericExceptionOnRun(
|
|
337
|
+
build_path=self._node_build_path(),
|
|
338
|
+
unique_id=self.node.unique_id,
|
|
339
|
+
exc=str(e),
|
|
340
|
+
node_info=get_node_info(),
|
|
341
|
+
)
|
|
342
|
+
)
|
|
343
|
+
fire_event(LogDebugStackTrace(exc_info=traceback.format_exc()))
|
|
344
|
+
|
|
345
|
+
return str(e)
|
|
346
|
+
|
|
347
|
+
def handle_exception(self, e: Exception, ctx: ExecutionContext) -> str:
|
|
348
|
+
if isinstance(e, DbtRuntimeError):
|
|
349
|
+
error = self._handle_catchable_exception(e, ctx)
|
|
350
|
+
elif isinstance(e, DbtInternalError):
|
|
351
|
+
error = self._handle_internal_exception(e, ctx)
|
|
352
|
+
else:
|
|
353
|
+
error = self._handle_generic_exception(e, ctx)
|
|
354
|
+
return error
|
|
355
|
+
|
|
356
|
+
def safe_run(self, manifest: Manifest):
|
|
357
|
+
started = time.time()
|
|
358
|
+
ctx = ExecutionContext(self.node)
|
|
359
|
+
error = None
|
|
360
|
+
result = None
|
|
361
|
+
|
|
362
|
+
try:
|
|
363
|
+
result = self.compile_and_execute(manifest, ctx)
|
|
364
|
+
except Exception as e:
|
|
365
|
+
error = self.handle_exception(e, ctx)
|
|
366
|
+
finally:
|
|
367
|
+
exc_str = self._safe_release_connection()
|
|
368
|
+
|
|
369
|
+
# if releasing failed and the result doesn't have an error yet, set
|
|
370
|
+
# an error
|
|
371
|
+
if (
|
|
372
|
+
exc_str is not None
|
|
373
|
+
and result is not None
|
|
374
|
+
and result.status != NodeStatus.Error
|
|
375
|
+
and error is None
|
|
376
|
+
):
|
|
377
|
+
error = exc_str
|
|
378
|
+
|
|
379
|
+
if error is not None:
|
|
380
|
+
result = self.error_result(ctx.node, error, started, ctx.timing)
|
|
381
|
+
elif result is not None:
|
|
382
|
+
result = self.from_run_result(result, started, ctx.timing)
|
|
383
|
+
else:
|
|
384
|
+
result = self.ephemeral_result(ctx.node, started, ctx.timing)
|
|
385
|
+
return result
|
|
386
|
+
|
|
387
|
+
def _safe_release_connection(self):
|
|
388
|
+
"""Try to release a connection. If an exception is hit, log and return
|
|
389
|
+
the error string.
|
|
390
|
+
"""
|
|
391
|
+
try:
|
|
392
|
+
self.adapter.release_connection()
|
|
393
|
+
except Exception as exc:
|
|
394
|
+
fire_event(
|
|
395
|
+
NodeConnectionReleaseError(
|
|
396
|
+
node_name=self.node.name, exc=str(exc), exc_info=traceback.format_exc()
|
|
397
|
+
)
|
|
398
|
+
)
|
|
399
|
+
return str(exc)
|
|
400
|
+
|
|
401
|
+
return None
|
|
402
|
+
|
|
403
|
+
def before_execute(self) -> None:
|
|
404
|
+
raise NotImplementedError("before_execute is not implemented")
|
|
405
|
+
|
|
406
|
+
def execute(self, compiled_node, manifest):
|
|
407
|
+
raise NotImplementedError("execute is not implemented")
|
|
408
|
+
|
|
409
|
+
def run(self, compiled_node, manifest):
|
|
410
|
+
return self.execute(compiled_node, manifest)
|
|
411
|
+
|
|
412
|
+
def after_execute(self, result) -> None:
|
|
413
|
+
raise NotImplementedError("after_execute is not implemented")
|
|
414
|
+
|
|
415
|
+
def _skip_caused_by_ephemeral_failure(self) -> bool:
|
|
416
|
+
if self.skip_cause is None or self.skip_cause.node is None:
|
|
417
|
+
return False
|
|
418
|
+
return self.skip_cause.node.is_ephemeral_model
|
|
419
|
+
|
|
420
|
+
def on_skip(self):
|
|
421
|
+
schema_name = getattr(self.node, "schema", "")
|
|
422
|
+
node_name = self.node.name
|
|
423
|
+
|
|
424
|
+
error_message = None
|
|
425
|
+
if not self.node.is_ephemeral_model:
|
|
426
|
+
# if this model was skipped due to an upstream ephemeral model
|
|
427
|
+
# failure, print a special 'error skip' message.
|
|
428
|
+
# Include skip_cause NodeStatus
|
|
429
|
+
group = group_lookup.get(self.node.unique_id)
|
|
430
|
+
|
|
431
|
+
if self._skip_caused_by_ephemeral_failure():
|
|
432
|
+
fire_event(
|
|
433
|
+
LogSkipBecauseError(
|
|
434
|
+
schema=schema_name,
|
|
435
|
+
relation=node_name,
|
|
436
|
+
index=self.node_index,
|
|
437
|
+
total=self.num_nodes,
|
|
438
|
+
status=self.skip_cause.status,
|
|
439
|
+
group=group,
|
|
440
|
+
)
|
|
441
|
+
)
|
|
442
|
+
# skip_cause here should be the run_result from the ephemeral model
|
|
443
|
+
print_run_result_error(result=self.skip_cause, newline=False)
|
|
444
|
+
if self.skip_cause is None: # mypy appeasement
|
|
445
|
+
raise DbtInternalError(
|
|
446
|
+
"Skip cause not set but skip was somehow caused by an ephemeral failure"
|
|
447
|
+
)
|
|
448
|
+
# set an error so dbt will exit with an error code
|
|
449
|
+
error_message = (
|
|
450
|
+
"Compilation Error in {}, caused by compilation error "
|
|
451
|
+
"in referenced ephemeral model {}".format(
|
|
452
|
+
self.node.unique_id, self.skip_cause.node.unique_id
|
|
453
|
+
)
|
|
454
|
+
)
|
|
455
|
+
else:
|
|
456
|
+
# 'skipped' nodes should not have a value for 'node_finished_at'
|
|
457
|
+
# they do have 'node_started_at', which is set in GraphRunnableTask.call_runner
|
|
458
|
+
self.node.update_event_status(node_status=RunStatus.Skipped)
|
|
459
|
+
fire_event(
|
|
460
|
+
SkippingDetails(
|
|
461
|
+
resource_type=self.node.resource_type,
|
|
462
|
+
schema=schema_name,
|
|
463
|
+
node_name=node_name,
|
|
464
|
+
index=self.node_index,
|
|
465
|
+
total=self.num_nodes,
|
|
466
|
+
node_info=self.node.node_info,
|
|
467
|
+
group=group,
|
|
468
|
+
)
|
|
469
|
+
)
|
|
470
|
+
|
|
471
|
+
node_result = RunResult.from_node(self.node, RunStatus.Skipped, error_message)
|
|
472
|
+
return node_result
|
|
473
|
+
|
|
474
|
+
def do_skip(self, cause=None) -> None:
|
|
475
|
+
self.skip = True
|
|
476
|
+
self.skip_cause = cause
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
def resource_types_from_args(
|
|
480
|
+
args: Flags, all_resource_values: Set[NodeType], default_resource_values: Set[NodeType]
|
|
481
|
+
) -> Set[NodeType]:
|
|
482
|
+
|
|
483
|
+
if not args.resource_types:
|
|
484
|
+
resource_types = default_resource_values
|
|
485
|
+
else:
|
|
486
|
+
# This is a list of strings, not NodeTypes
|
|
487
|
+
arg_resource_types = set(args.resource_types)
|
|
488
|
+
|
|
489
|
+
if "all" in arg_resource_types:
|
|
490
|
+
arg_resource_types.remove("all")
|
|
491
|
+
arg_resource_types.update(all_resource_values)
|
|
492
|
+
if "default" in arg_resource_types:
|
|
493
|
+
arg_resource_types.remove("default")
|
|
494
|
+
arg_resource_types.update(default_resource_values)
|
|
495
|
+
# Convert to a set of NodeTypes now that the non-NodeType strings are gone
|
|
496
|
+
resource_types = set([NodeType(rt) for rt in list(arg_resource_types)])
|
|
497
|
+
|
|
498
|
+
if args.exclude_resource_types:
|
|
499
|
+
# Convert from a list of strings to a set of NodeTypes
|
|
500
|
+
exclude_resource_types = set([NodeType(rt) for rt in args.exclude_resource_types])
|
|
501
|
+
resource_types = resource_types - exclude_resource_types
|
|
502
|
+
|
|
503
|
+
return resource_types
|