dvt-core 1.11.0b4__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.
Potentially problematic release.
This version of dvt-core might be problematic. Click here for more details.
- dvt/__init__.py +7 -0
- dvt/_pydantic_shim.py +26 -0
- dvt/adapters/__init__.py +16 -0
- dvt/adapters/multi_adapter_manager.py +268 -0
- dvt/artifacts/__init__.py +0 -0
- dvt/artifacts/exceptions/__init__.py +1 -0
- dvt/artifacts/exceptions/schemas.py +31 -0
- dvt/artifacts/resources/__init__.py +116 -0
- dvt/artifacts/resources/base.py +68 -0
- dvt/artifacts/resources/types.py +93 -0
- dvt/artifacts/resources/v1/analysis.py +10 -0
- dvt/artifacts/resources/v1/catalog.py +23 -0
- dvt/artifacts/resources/v1/components.py +275 -0
- dvt/artifacts/resources/v1/config.py +282 -0
- dvt/artifacts/resources/v1/documentation.py +11 -0
- dvt/artifacts/resources/v1/exposure.py +52 -0
- dvt/artifacts/resources/v1/function.py +53 -0
- dvt/artifacts/resources/v1/generic_test.py +32 -0
- dvt/artifacts/resources/v1/group.py +22 -0
- dvt/artifacts/resources/v1/hook.py +11 -0
- dvt/artifacts/resources/v1/macro.py +30 -0
- dvt/artifacts/resources/v1/metric.py +173 -0
- dvt/artifacts/resources/v1/model.py +146 -0
- dvt/artifacts/resources/v1/owner.py +10 -0
- dvt/artifacts/resources/v1/saved_query.py +112 -0
- dvt/artifacts/resources/v1/seed.py +42 -0
- dvt/artifacts/resources/v1/semantic_layer_components.py +72 -0
- dvt/artifacts/resources/v1/semantic_model.py +315 -0
- dvt/artifacts/resources/v1/singular_test.py +14 -0
- dvt/artifacts/resources/v1/snapshot.py +92 -0
- dvt/artifacts/resources/v1/source_definition.py +85 -0
- dvt/artifacts/resources/v1/sql_operation.py +10 -0
- dvt/artifacts/resources/v1/unit_test_definition.py +78 -0
- dvt/artifacts/schemas/__init__.py +0 -0
- dvt/artifacts/schemas/base.py +191 -0
- dvt/artifacts/schemas/batch_results.py +24 -0
- dvt/artifacts/schemas/catalog/__init__.py +12 -0
- dvt/artifacts/schemas/catalog/v1/__init__.py +0 -0
- dvt/artifacts/schemas/catalog/v1/catalog.py +60 -0
- dvt/artifacts/schemas/freshness/__init__.py +1 -0
- dvt/artifacts/schemas/freshness/v3/__init__.py +0 -0
- dvt/artifacts/schemas/freshness/v3/freshness.py +159 -0
- dvt/artifacts/schemas/manifest/__init__.py +2 -0
- dvt/artifacts/schemas/manifest/v12/__init__.py +0 -0
- dvt/artifacts/schemas/manifest/v12/manifest.py +212 -0
- dvt/artifacts/schemas/results.py +148 -0
- dvt/artifacts/schemas/run/__init__.py +2 -0
- dvt/artifacts/schemas/run/v5/__init__.py +0 -0
- dvt/artifacts/schemas/run/v5/run.py +184 -0
- dvt/artifacts/schemas/upgrades/__init__.py +4 -0
- dvt/artifacts/schemas/upgrades/upgrade_manifest.py +174 -0
- dvt/artifacts/schemas/upgrades/upgrade_manifest_dbt_version.py +2 -0
- dvt/artifacts/utils/validation.py +153 -0
- dvt/cli/__init__.py +1 -0
- dvt/cli/context.py +16 -0
- dvt/cli/exceptions.py +56 -0
- dvt/cli/flags.py +558 -0
- dvt/cli/main.py +971 -0
- dvt/cli/option_types.py +121 -0
- dvt/cli/options.py +79 -0
- dvt/cli/params.py +803 -0
- dvt/cli/requires.py +478 -0
- dvt/cli/resolvers.py +32 -0
- dvt/cli/types.py +40 -0
- dvt/clients/__init__.py +0 -0
- dvt/clients/checked_load.py +82 -0
- dvt/clients/git.py +164 -0
- dvt/clients/jinja.py +206 -0
- dvt/clients/jinja_static.py +245 -0
- dvt/clients/registry.py +192 -0
- dvt/clients/yaml_helper.py +68 -0
- dvt/compilation.py +833 -0
- dvt/compute/__init__.py +26 -0
- dvt/compute/base.py +288 -0
- dvt/compute/engines/__init__.py +13 -0
- dvt/compute/engines/duckdb_engine.py +368 -0
- dvt/compute/engines/spark_engine.py +273 -0
- dvt/compute/query_analyzer.py +212 -0
- dvt/compute/router.py +483 -0
- dvt/config/__init__.py +4 -0
- dvt/config/catalogs.py +95 -0
- dvt/config/compute_config.py +406 -0
- dvt/config/profile.py +411 -0
- dvt/config/profiles_v2.py +464 -0
- dvt/config/project.py +893 -0
- dvt/config/renderer.py +232 -0
- dvt/config/runtime.py +491 -0
- dvt/config/selectors.py +209 -0
- dvt/config/utils.py +78 -0
- dvt/connectors/.gitignore +6 -0
- dvt/connectors/README.md +306 -0
- dvt/connectors/catalog.yml +217 -0
- dvt/connectors/download_connectors.py +300 -0
- dvt/constants.py +29 -0
- dvt/context/__init__.py +0 -0
- dvt/context/base.py +746 -0
- dvt/context/configured.py +136 -0
- dvt/context/context_config.py +350 -0
- dvt/context/docs.py +82 -0
- dvt/context/exceptions_jinja.py +179 -0
- dvt/context/macro_resolver.py +195 -0
- dvt/context/macros.py +171 -0
- dvt/context/manifest.py +73 -0
- dvt/context/providers.py +2198 -0
- dvt/context/query_header.py +14 -0
- dvt/context/secret.py +59 -0
- dvt/context/target.py +74 -0
- dvt/contracts/__init__.py +0 -0
- dvt/contracts/files.py +413 -0
- dvt/contracts/graph/__init__.py +0 -0
- dvt/contracts/graph/manifest.py +1904 -0
- dvt/contracts/graph/metrics.py +98 -0
- dvt/contracts/graph/model_config.py +71 -0
- dvt/contracts/graph/node_args.py +42 -0
- dvt/contracts/graph/nodes.py +1806 -0
- dvt/contracts/graph/semantic_manifest.py +233 -0
- dvt/contracts/graph/unparsed.py +812 -0
- dvt/contracts/project.py +417 -0
- dvt/contracts/results.py +53 -0
- dvt/contracts/selection.py +23 -0
- dvt/contracts/sql.py +86 -0
- dvt/contracts/state.py +69 -0
- dvt/contracts/util.py +46 -0
- dvt/deprecations.py +347 -0
- dvt/deps/__init__.py +0 -0
- dvt/deps/base.py +153 -0
- dvt/deps/git.py +196 -0
- dvt/deps/local.py +80 -0
- dvt/deps/registry.py +131 -0
- dvt/deps/resolver.py +149 -0
- dvt/deps/tarball.py +121 -0
- dvt/docs/source/_ext/dbt_click.py +118 -0
- dvt/docs/source/conf.py +32 -0
- dvt/env_vars.py +64 -0
- dvt/event_time/event_time.py +40 -0
- dvt/event_time/sample_window.py +60 -0
- dvt/events/__init__.py +16 -0
- dvt/events/base_types.py +37 -0
- dvt/events/core_types_pb2.py +2 -0
- dvt/events/logging.py +109 -0
- dvt/events/types.py +2534 -0
- dvt/exceptions.py +1487 -0
- dvt/flags.py +89 -0
- dvt/graph/__init__.py +11 -0
- dvt/graph/cli.py +248 -0
- dvt/graph/graph.py +172 -0
- dvt/graph/queue.py +213 -0
- dvt/graph/selector.py +375 -0
- dvt/graph/selector_methods.py +976 -0
- dvt/graph/selector_spec.py +223 -0
- dvt/graph/thread_pool.py +18 -0
- dvt/hooks.py +21 -0
- dvt/include/README.md +49 -0
- dvt/include/__init__.py +3 -0
- dvt/include/global_project.py +4 -0
- dvt/include/starter_project/.gitignore +4 -0
- dvt/include/starter_project/README.md +15 -0
- dvt/include/starter_project/__init__.py +3 -0
- dvt/include/starter_project/analyses/.gitkeep +0 -0
- dvt/include/starter_project/dvt_project.yml +36 -0
- dvt/include/starter_project/macros/.gitkeep +0 -0
- dvt/include/starter_project/models/example/my_first_dbt_model.sql +27 -0
- dvt/include/starter_project/models/example/my_second_dbt_model.sql +6 -0
- dvt/include/starter_project/models/example/schema.yml +21 -0
- dvt/include/starter_project/seeds/.gitkeep +0 -0
- dvt/include/starter_project/snapshots/.gitkeep +0 -0
- dvt/include/starter_project/tests/.gitkeep +0 -0
- dvt/internal_deprecations.py +27 -0
- dvt/jsonschemas/__init__.py +3 -0
- dvt/jsonschemas/jsonschemas.py +309 -0
- dvt/jsonschemas/project/0.0.110.json +4717 -0
- dvt/jsonschemas/project/0.0.85.json +2015 -0
- dvt/jsonschemas/resources/0.0.110.json +2636 -0
- dvt/jsonschemas/resources/0.0.85.json +2536 -0
- dvt/jsonschemas/resources/latest.json +6773 -0
- dvt/links.py +4 -0
- dvt/materializations/__init__.py +0 -0
- dvt/materializations/incremental/__init__.py +0 -0
- dvt/materializations/incremental/microbatch.py +235 -0
- dvt/mp_context.py +8 -0
- dvt/node_types.py +37 -0
- dvt/parser/__init__.py +23 -0
- dvt/parser/analysis.py +21 -0
- dvt/parser/base.py +549 -0
- dvt/parser/common.py +267 -0
- dvt/parser/docs.py +52 -0
- dvt/parser/fixtures.py +51 -0
- dvt/parser/functions.py +30 -0
- dvt/parser/generic_test.py +100 -0
- dvt/parser/generic_test_builders.py +334 -0
- dvt/parser/hooks.py +119 -0
- dvt/parser/macros.py +137 -0
- dvt/parser/manifest.py +2204 -0
- dvt/parser/models.py +574 -0
- dvt/parser/partial.py +1179 -0
- dvt/parser/read_files.py +445 -0
- dvt/parser/schema_generic_tests.py +423 -0
- dvt/parser/schema_renderer.py +111 -0
- dvt/parser/schema_yaml_readers.py +936 -0
- dvt/parser/schemas.py +1467 -0
- dvt/parser/search.py +149 -0
- dvt/parser/seeds.py +28 -0
- dvt/parser/singular_test.py +20 -0
- dvt/parser/snapshots.py +44 -0
- dvt/parser/sources.py +557 -0
- dvt/parser/sql.py +63 -0
- dvt/parser/unit_tests.py +622 -0
- dvt/plugins/__init__.py +20 -0
- dvt/plugins/contracts.py +10 -0
- dvt/plugins/exceptions.py +2 -0
- dvt/plugins/manager.py +164 -0
- dvt/plugins/manifest.py +21 -0
- dvt/profiler.py +20 -0
- dvt/py.typed +1 -0
- dvt/runners/__init__.py +2 -0
- dvt/runners/exposure_runner.py +7 -0
- dvt/runners/no_op_runner.py +46 -0
- dvt/runners/saved_query_runner.py +7 -0
- dvt/selected_resources.py +8 -0
- dvt/task/__init__.py +0 -0
- dvt/task/base.py +504 -0
- dvt/task/build.py +197 -0
- dvt/task/clean.py +57 -0
- dvt/task/clone.py +162 -0
- dvt/task/compile.py +151 -0
- dvt/task/compute.py +366 -0
- dvt/task/debug.py +650 -0
- dvt/task/deps.py +280 -0
- dvt/task/docs/__init__.py +3 -0
- dvt/task/docs/generate.py +408 -0
- dvt/task/docs/index.html +250 -0
- dvt/task/docs/serve.py +28 -0
- dvt/task/freshness.py +323 -0
- dvt/task/function.py +122 -0
- dvt/task/group_lookup.py +46 -0
- dvt/task/init.py +374 -0
- dvt/task/list.py +237 -0
- dvt/task/printer.py +176 -0
- dvt/task/profiles.py +256 -0
- dvt/task/retry.py +175 -0
- dvt/task/run.py +1146 -0
- dvt/task/run_operation.py +142 -0
- dvt/task/runnable.py +802 -0
- dvt/task/seed.py +104 -0
- dvt/task/show.py +150 -0
- dvt/task/snapshot.py +57 -0
- dvt/task/sql.py +111 -0
- dvt/task/test.py +464 -0
- dvt/tests/fixtures/__init__.py +1 -0
- dvt/tests/fixtures/project.py +620 -0
- dvt/tests/util.py +651 -0
- dvt/tracking.py +529 -0
- dvt/utils/__init__.py +3 -0
- dvt/utils/artifact_upload.py +151 -0
- dvt/utils/utils.py +408 -0
- dvt/version.py +249 -0
- dvt_core-1.11.0b4.dist-info/METADATA +252 -0
- dvt_core-1.11.0b4.dist-info/RECORD +261 -0
- dvt_core-1.11.0b4.dist-info/WHEEL +5 -0
- dvt_core-1.11.0b4.dist-info/entry_points.txt +2 -0
- dvt_core-1.11.0b4.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import re
|
|
3
|
+
from abc import ABCMeta, abstractmethod
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from typing import Any, Dict, Iterable, Iterator, List, Optional, Set, Tuple, Union
|
|
6
|
+
|
|
7
|
+
from dvt.exceptions import InvalidSelectorError
|
|
8
|
+
from dvt.flags import get_flags
|
|
9
|
+
|
|
10
|
+
from dbt_common.dataclass_schema import StrEnum, dbtClassMixin
|
|
11
|
+
from dbt_common.exceptions import DbtRuntimeError
|
|
12
|
+
|
|
13
|
+
from .graph import UniqueId
|
|
14
|
+
from .selector_methods import MethodName
|
|
15
|
+
|
|
16
|
+
RAW_SELECTOR_PATTERN = re.compile(
|
|
17
|
+
r"\A"
|
|
18
|
+
r"(?P<childrens_parents>(\@))?"
|
|
19
|
+
r"(?P<parents>((?P<parents_depth>(\d*))\+))?"
|
|
20
|
+
r"((?P<method>([\w.]+)):)?(?P<value>(.*?))"
|
|
21
|
+
r"(?P<children>(\+(?P<children_depth>(\d*))))?"
|
|
22
|
+
r"\Z"
|
|
23
|
+
)
|
|
24
|
+
SELECTOR_METHOD_SEPARATOR = "."
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class IndirectSelection(StrEnum):
|
|
28
|
+
Eager = "eager"
|
|
29
|
+
Cautious = "cautious"
|
|
30
|
+
Buildable = "buildable"
|
|
31
|
+
Empty = "empty"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _probably_path(value: str):
|
|
35
|
+
"""Decide if the value is probably a path. Windows has two path separators, so
|
|
36
|
+
we should check both sep ('\\') and altsep ('/') there.
|
|
37
|
+
"""
|
|
38
|
+
if os.path.sep in value:
|
|
39
|
+
return True
|
|
40
|
+
elif os.path.altsep is not None and os.path.altsep in value:
|
|
41
|
+
return True
|
|
42
|
+
else:
|
|
43
|
+
return False
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _match_to_int(match: Dict[str, str], key: str) -> Optional[int]:
|
|
47
|
+
raw = match.get(key)
|
|
48
|
+
# turn the empty string into None, too.
|
|
49
|
+
if not raw:
|
|
50
|
+
return None
|
|
51
|
+
try:
|
|
52
|
+
return int(raw)
|
|
53
|
+
except ValueError as exc:
|
|
54
|
+
raise DbtRuntimeError(f"Invalid node spec - could not handle parent depth {raw}") from exc
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
SelectionSpec = Union[
|
|
58
|
+
"SelectionCriteria",
|
|
59
|
+
"SelectionIntersection",
|
|
60
|
+
"SelectionDifference",
|
|
61
|
+
"SelectionUnion",
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@dataclass
|
|
66
|
+
class SelectionCriteria:
|
|
67
|
+
raw: Any
|
|
68
|
+
method: MethodName
|
|
69
|
+
method_arguments: List[str]
|
|
70
|
+
value: Any
|
|
71
|
+
childrens_parents: bool
|
|
72
|
+
parents: bool
|
|
73
|
+
parents_depth: Optional[int]
|
|
74
|
+
children: bool
|
|
75
|
+
children_depth: Optional[int]
|
|
76
|
+
indirect_selection: IndirectSelection = IndirectSelection.Eager
|
|
77
|
+
|
|
78
|
+
def __post_init__(self):
|
|
79
|
+
if self.children and self.childrens_parents:
|
|
80
|
+
raise DbtRuntimeError(
|
|
81
|
+
f'Invalid node spec {self.raw} - "@" prefix and "+" suffix ' "are incompatible"
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
@classmethod
|
|
85
|
+
def default_method(cls, value: str) -> MethodName:
|
|
86
|
+
if _probably_path(value):
|
|
87
|
+
return MethodName.Path
|
|
88
|
+
elif value.lower().endswith((".sql", ".py", ".csv")):
|
|
89
|
+
return MethodName.File
|
|
90
|
+
else:
|
|
91
|
+
return MethodName.FQN
|
|
92
|
+
|
|
93
|
+
@classmethod
|
|
94
|
+
def parse_method(cls, groupdict: Dict[str, Any]) -> Tuple[MethodName, List[str]]:
|
|
95
|
+
raw_method = groupdict.get("method")
|
|
96
|
+
if raw_method is None:
|
|
97
|
+
return cls.default_method(groupdict["value"]), []
|
|
98
|
+
|
|
99
|
+
method_parts: List[str] = raw_method.split(SELECTOR_METHOD_SEPARATOR)
|
|
100
|
+
try:
|
|
101
|
+
method_name = MethodName(method_parts[0])
|
|
102
|
+
except ValueError as exc:
|
|
103
|
+
raise InvalidSelectorError(f"'{method_parts[0]}' is not a valid method name") from exc
|
|
104
|
+
|
|
105
|
+
# Following is for cases like config.severity and config.materialized
|
|
106
|
+
method_arguments: List[str] = method_parts[1:]
|
|
107
|
+
|
|
108
|
+
return method_name, method_arguments
|
|
109
|
+
|
|
110
|
+
@classmethod
|
|
111
|
+
def selection_criteria_from_dict(
|
|
112
|
+
cls,
|
|
113
|
+
raw: Any,
|
|
114
|
+
dct: Dict[str, Any],
|
|
115
|
+
) -> "SelectionCriteria":
|
|
116
|
+
if "value" not in dct:
|
|
117
|
+
raise DbtRuntimeError(f'Invalid node spec "{raw}" - no search value!')
|
|
118
|
+
method_name, method_arguments = cls.parse_method(dct)
|
|
119
|
+
|
|
120
|
+
parents_depth = _match_to_int(dct, "parents_depth")
|
|
121
|
+
children_depth = _match_to_int(dct, "children_depth")
|
|
122
|
+
|
|
123
|
+
# If defined field in selector, override CLI flag
|
|
124
|
+
indirect_selection = IndirectSelection(
|
|
125
|
+
dct.get("indirect_selection", get_flags().INDIRECT_SELECTION)
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
return cls(
|
|
129
|
+
raw=raw,
|
|
130
|
+
method=method_name,
|
|
131
|
+
method_arguments=method_arguments,
|
|
132
|
+
value=dct["value"],
|
|
133
|
+
childrens_parents=bool(dct.get("childrens_parents")),
|
|
134
|
+
parents=bool(dct.get("parents")),
|
|
135
|
+
parents_depth=parents_depth,
|
|
136
|
+
children=bool(dct.get("children")),
|
|
137
|
+
children_depth=children_depth,
|
|
138
|
+
indirect_selection=indirect_selection,
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
@classmethod
|
|
142
|
+
def dict_from_single_spec(cls, raw: str):
|
|
143
|
+
result = RAW_SELECTOR_PATTERN.match(raw)
|
|
144
|
+
if result is None:
|
|
145
|
+
return {"error": "Invalid selector spec"}
|
|
146
|
+
dct: Dict[str, Any] = result.groupdict()
|
|
147
|
+
method_name, method_arguments = cls.parse_method(dct)
|
|
148
|
+
meth_name = str(method_name)
|
|
149
|
+
if method_arguments:
|
|
150
|
+
meth_name += "." + ".".join(method_arguments)
|
|
151
|
+
dct["method"] = meth_name
|
|
152
|
+
dct = {k: v for k, v in dct.items() if (v is not None and v != "")}
|
|
153
|
+
if "childrens_parents" in dct:
|
|
154
|
+
dct["childrens_parents"] = bool(dct.get("childrens_parents"))
|
|
155
|
+
if "parents" in dct:
|
|
156
|
+
dct["parents"] = bool(dct.get("parents"))
|
|
157
|
+
if "children" in dct:
|
|
158
|
+
dct["children"] = bool(dct.get("children"))
|
|
159
|
+
return dct
|
|
160
|
+
|
|
161
|
+
@classmethod
|
|
162
|
+
def from_single_spec(cls, raw: str) -> "SelectionCriteria":
|
|
163
|
+
result = RAW_SELECTOR_PATTERN.match(raw)
|
|
164
|
+
if result is None:
|
|
165
|
+
# bad spec!
|
|
166
|
+
raise DbtRuntimeError(f'Invalid selector spec "{raw}"')
|
|
167
|
+
|
|
168
|
+
return cls.selection_criteria_from_dict(raw, result.groupdict())
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
class BaseSelectionGroup(dbtClassMixin, Iterable[SelectionSpec], metaclass=ABCMeta):
|
|
172
|
+
def __init__(
|
|
173
|
+
self,
|
|
174
|
+
components: Iterable[SelectionSpec],
|
|
175
|
+
indirect_selection: IndirectSelection = IndirectSelection.Eager,
|
|
176
|
+
expect_exists: bool = False,
|
|
177
|
+
raw: Any = None,
|
|
178
|
+
) -> None:
|
|
179
|
+
self.components: List[SelectionSpec] = list(components)
|
|
180
|
+
self.expect_exists = expect_exists
|
|
181
|
+
self.raw = raw
|
|
182
|
+
self.indirect_selection = indirect_selection
|
|
183
|
+
|
|
184
|
+
def __iter__(self) -> Iterator[SelectionSpec]:
|
|
185
|
+
for component in self.components:
|
|
186
|
+
yield component
|
|
187
|
+
|
|
188
|
+
@abstractmethod
|
|
189
|
+
def combine_selections(
|
|
190
|
+
self,
|
|
191
|
+
selections: List[Set[UniqueId]],
|
|
192
|
+
) -> Set[UniqueId]:
|
|
193
|
+
raise NotImplementedError("_combine_selections not implemented!")
|
|
194
|
+
|
|
195
|
+
def combined(self, selections: List[Set[UniqueId]]) -> Set[UniqueId]:
|
|
196
|
+
if not selections:
|
|
197
|
+
return set()
|
|
198
|
+
|
|
199
|
+
return self.combine_selections(selections)
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
class SelectionIntersection(BaseSelectionGroup):
|
|
203
|
+
def combine_selections(
|
|
204
|
+
self,
|
|
205
|
+
selections: List[Set[UniqueId]],
|
|
206
|
+
) -> Set[UniqueId]:
|
|
207
|
+
return set.intersection(*selections)
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
class SelectionDifference(BaseSelectionGroup):
|
|
211
|
+
def combine_selections(
|
|
212
|
+
self,
|
|
213
|
+
selections: List[Set[UniqueId]],
|
|
214
|
+
) -> Set[UniqueId]:
|
|
215
|
+
return set.difference(*selections)
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
class SelectionUnion(BaseSelectionGroup):
|
|
219
|
+
def combine_selections(
|
|
220
|
+
self,
|
|
221
|
+
selections: List[Set[UniqueId]],
|
|
222
|
+
) -> Set[UniqueId]:
|
|
223
|
+
return set.union(*selections)
|
dvt/graph/thread_pool.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from multiprocessing.pool import ThreadPool
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class DbtThreadPool(ThreadPool):
|
|
7
|
+
"""A ThreadPool that tracks whether or not it's been closed"""
|
|
8
|
+
|
|
9
|
+
def __init__(self, *args, **kwargs):
|
|
10
|
+
super().__init__(*args, **kwargs)
|
|
11
|
+
self.closed = False
|
|
12
|
+
|
|
13
|
+
def close(self):
|
|
14
|
+
self.closed = True
|
|
15
|
+
super().close()
|
|
16
|
+
|
|
17
|
+
def is_closed(self):
|
|
18
|
+
return self.closed
|
dvt/hooks.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from typing import Any, Dict, Union
|
|
3
|
+
|
|
4
|
+
from dbt_common.dataclass_schema import StrEnum
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ModelHookType(StrEnum):
|
|
8
|
+
PreHook = "pre-hook"
|
|
9
|
+
PostHook = "post-hook"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def get_hook_dict(source: Union[str, Dict[str, Any]]) -> Dict[str, Any]:
|
|
13
|
+
"""From a source string-or-dict, get a dictionary that can be passed to
|
|
14
|
+
Hook.from_dict
|
|
15
|
+
"""
|
|
16
|
+
if isinstance(source, dict):
|
|
17
|
+
return source
|
|
18
|
+
try:
|
|
19
|
+
return json.loads(source)
|
|
20
|
+
except ValueError:
|
|
21
|
+
return {"sql": source}
|
dvt/include/README.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Include Module
|
|
2
|
+
|
|
3
|
+
The Include module is responsible for the starter project scaffold.
|
|
4
|
+
|
|
5
|
+
# Directories
|
|
6
|
+
|
|
7
|
+
## `starter_project`
|
|
8
|
+
Produces the default project after running the `dbt init` command for the CLI. `dbt-cloud` initializes the project by using [dbt-starter-project](https://github.com/dbt-labs/dbt-starter-project).
|
|
9
|
+
|
|
10
|
+
# adapter.dispatch
|
|
11
|
+
Packages (e.g. `include` directories of adapters, any [hub](https://hub.getdbt.com/)-hosted package) can be interpreted as namespaces of functions a.k.a macros. In `dbt`'s macrospace, we take advantage of the multiple dispatch programming language concept. In short, multiple dispatch supports dynamic searching for a function across several namespaces—usually in a manually specified manner/order.
|
|
12
|
+
|
|
13
|
+
Adapters can have their own implementation of the same macro X. For example, a macro executed by `dbt-redshift` may need a specific implementation different from `dbt-snowflake`'s macro. We use multiple dispatch via `adapter.dispatch`, a Jinja function, which enables polymorphic macro invocations. The chosen implementation is selected according to what the `adapter` object is set to at runtime (it could be for redshift, postgres, and so on).
|
|
14
|
+
|
|
15
|
+
For more on this object, check out the dbt docs [here](https://docs.getdbt.com/reference/dbt-jinja-functions/adapter).
|
|
16
|
+
|
|
17
|
+
# dbt and database adapter python package interop
|
|
18
|
+
|
|
19
|
+
Let’s say we have a fictional python app named `dbt-core` with this structure
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
dbt
|
|
23
|
+
├── adapters
|
|
24
|
+
│ └── base.py
|
|
25
|
+
├── cli.py
|
|
26
|
+
└── main.py
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`pip install dbt-core` will install this application in my python environment, maintaining the same structure. Note that `dbt.adapters` only contains a `base.py`. In this example, we can assume that base.py includes an abstract class for creating connections. Let’s say we wanted to create an postgres adapter that this app could use, and can be installed independently. We can create a python package with the following structure called `dbt-postgres`
|
|
30
|
+
```
|
|
31
|
+
dbt
|
|
32
|
+
└── adapters
|
|
33
|
+
└── postgres
|
|
34
|
+
└── impl.py
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
`pip install dbt-postgres` will install this package in the python environment, maintaining the same structure again. Let’s say `impl.py` imports `dbt.adapters.base` and implements a concrete class inheriting from the abstract class in `base.py` from the `dbt-core` package. Since our top level package is named the same in both packages, `pip` will put this in the same place. We end up with this installed in our python environment.
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
dbt
|
|
41
|
+
├── adapters
|
|
42
|
+
│ ├── base.py
|
|
43
|
+
│ └── postgres
|
|
44
|
+
│ └── impl.py
|
|
45
|
+
├── cli.py
|
|
46
|
+
└── main.py
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
`dbt.adapters` now has a postgres module that dbt can easily find and call directly. dbt and its adapters follows the same type of file structure convention. This is the magic that allows you to import `dbt.*` in database adapters, and using a factory pattern in dbt-core, we can create instances of concrete classes defined in the database adapter packages (for creating connections, defining database configuration, defining credentials, etc.)
|
dvt/include/__init__.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Welcome to your new dbt project!
|
|
2
|
+
|
|
3
|
+
### Using the starter project
|
|
4
|
+
|
|
5
|
+
Try running the following commands:
|
|
6
|
+
- dbt run
|
|
7
|
+
- dbt test
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Resources:
|
|
11
|
+
- Learn more about dbt [in the docs](https://docs.getdbt.com/docs/introduction)
|
|
12
|
+
- Check out [Discourse](https://discourse.getdbt.com/) for commonly asked questions and answers
|
|
13
|
+
- Join the [chat](https://community.getdbt.com/) on Slack for live discussions and support
|
|
14
|
+
- Find [dbt events](https://events.getdbt.com) near you
|
|
15
|
+
- Check out [the blog](https://blog.getdbt.com/) for the latest news on dbt's development and best practices
|
|
File without changes
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
|
|
2
|
+
# Name your project! Project names should contain only lowercase characters
|
|
3
|
+
# and underscores. A good package name should reflect your organization's
|
|
4
|
+
# name or the intended use of these models
|
|
5
|
+
name: '{project_name}'
|
|
6
|
+
version: '1.0.0'
|
|
7
|
+
|
|
8
|
+
# This setting configures which "profile" dbt uses for this project.
|
|
9
|
+
profile: '{profile_name}'
|
|
10
|
+
|
|
11
|
+
# These configurations specify where dbt should look for different types of files.
|
|
12
|
+
# The `model-paths` config, for example, states that models in this project can be
|
|
13
|
+
# found in the "models/" directory. You probably won't need to change these!
|
|
14
|
+
model-paths: ["models"]
|
|
15
|
+
analysis-paths: ["analyses"]
|
|
16
|
+
test-paths: ["tests"]
|
|
17
|
+
seed-paths: ["seeds"]
|
|
18
|
+
macro-paths: ["macros"]
|
|
19
|
+
snapshot-paths: ["snapshots"]
|
|
20
|
+
|
|
21
|
+
clean-targets: # directories to be removed by `dbt clean`
|
|
22
|
+
- "target"
|
|
23
|
+
- "dbt_packages"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# Configuring models
|
|
27
|
+
# Full documentation: https://docs.getdbt.com/docs/configuring-models
|
|
28
|
+
|
|
29
|
+
# In this example config, we tell dbt to build all models in the example/
|
|
30
|
+
# directory as views. These settings can be overridden in the individual model
|
|
31
|
+
# files using the `{{{{ config(...) }}}}` macro.
|
|
32
|
+
models:
|
|
33
|
+
{project_name}:
|
|
34
|
+
# Config indicated by + and applies to all files under models/example/
|
|
35
|
+
example:
|
|
36
|
+
+materialized: view
|
|
File without changes
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
|
|
2
|
+
/*
|
|
3
|
+
Welcome to your first dbt model!
|
|
4
|
+
Did you know that you can also configure models directly within SQL files?
|
|
5
|
+
This will override configurations stated in dbt_project.yml
|
|
6
|
+
|
|
7
|
+
Try changing "table" to "view" below
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
{{ config(materialized='table') }}
|
|
11
|
+
|
|
12
|
+
with source_data as (
|
|
13
|
+
|
|
14
|
+
select 1 as id
|
|
15
|
+
union all
|
|
16
|
+
select null as id
|
|
17
|
+
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
select *
|
|
21
|
+
from source_data
|
|
22
|
+
|
|
23
|
+
/*
|
|
24
|
+
Uncomment the line below to remove records with null `id` values
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
-- where id is not null
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
|
|
2
|
+
version: 2
|
|
3
|
+
|
|
4
|
+
models:
|
|
5
|
+
- name: my_first_dbt_model
|
|
6
|
+
description: "A starter dbt model"
|
|
7
|
+
columns:
|
|
8
|
+
- name: id
|
|
9
|
+
description: "The primary key for this table"
|
|
10
|
+
data_tests:
|
|
11
|
+
- unique
|
|
12
|
+
- not_null
|
|
13
|
+
|
|
14
|
+
- name: my_second_dbt_model
|
|
15
|
+
description: "A starter dbt model"
|
|
16
|
+
columns:
|
|
17
|
+
- name: id
|
|
18
|
+
description: "The primary key for this table"
|
|
19
|
+
data_tests:
|
|
20
|
+
- unique
|
|
21
|
+
- not_null
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import functools
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
from dvt.events.types import InternalDeprecation
|
|
5
|
+
|
|
6
|
+
from dbt_common.events.functions import warn_or_error
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def deprecated(suggested_action: str, version: str, reason: Optional[str]):
|
|
10
|
+
def inner(func):
|
|
11
|
+
@functools.wraps(func)
|
|
12
|
+
def wrapped(*args, **kwargs):
|
|
13
|
+
name = func.__name__
|
|
14
|
+
|
|
15
|
+
warn_or_error(
|
|
16
|
+
InternalDeprecation(
|
|
17
|
+
name=name,
|
|
18
|
+
suggested_action=suggested_action,
|
|
19
|
+
version=version,
|
|
20
|
+
reason=reason,
|
|
21
|
+
)
|
|
22
|
+
) # TODO: pass in event?
|
|
23
|
+
return func(*args, **kwargs)
|
|
24
|
+
|
|
25
|
+
return wrapped
|
|
26
|
+
|
|
27
|
+
return inner
|