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.

Files changed (261) hide show
  1. dvt/__init__.py +7 -0
  2. dvt/_pydantic_shim.py +26 -0
  3. dvt/adapters/__init__.py +16 -0
  4. dvt/adapters/multi_adapter_manager.py +268 -0
  5. dvt/artifacts/__init__.py +0 -0
  6. dvt/artifacts/exceptions/__init__.py +1 -0
  7. dvt/artifacts/exceptions/schemas.py +31 -0
  8. dvt/artifacts/resources/__init__.py +116 -0
  9. dvt/artifacts/resources/base.py +68 -0
  10. dvt/artifacts/resources/types.py +93 -0
  11. dvt/artifacts/resources/v1/analysis.py +10 -0
  12. dvt/artifacts/resources/v1/catalog.py +23 -0
  13. dvt/artifacts/resources/v1/components.py +275 -0
  14. dvt/artifacts/resources/v1/config.py +282 -0
  15. dvt/artifacts/resources/v1/documentation.py +11 -0
  16. dvt/artifacts/resources/v1/exposure.py +52 -0
  17. dvt/artifacts/resources/v1/function.py +53 -0
  18. dvt/artifacts/resources/v1/generic_test.py +32 -0
  19. dvt/artifacts/resources/v1/group.py +22 -0
  20. dvt/artifacts/resources/v1/hook.py +11 -0
  21. dvt/artifacts/resources/v1/macro.py +30 -0
  22. dvt/artifacts/resources/v1/metric.py +173 -0
  23. dvt/artifacts/resources/v1/model.py +146 -0
  24. dvt/artifacts/resources/v1/owner.py +10 -0
  25. dvt/artifacts/resources/v1/saved_query.py +112 -0
  26. dvt/artifacts/resources/v1/seed.py +42 -0
  27. dvt/artifacts/resources/v1/semantic_layer_components.py +72 -0
  28. dvt/artifacts/resources/v1/semantic_model.py +315 -0
  29. dvt/artifacts/resources/v1/singular_test.py +14 -0
  30. dvt/artifacts/resources/v1/snapshot.py +92 -0
  31. dvt/artifacts/resources/v1/source_definition.py +85 -0
  32. dvt/artifacts/resources/v1/sql_operation.py +10 -0
  33. dvt/artifacts/resources/v1/unit_test_definition.py +78 -0
  34. dvt/artifacts/schemas/__init__.py +0 -0
  35. dvt/artifacts/schemas/base.py +191 -0
  36. dvt/artifacts/schemas/batch_results.py +24 -0
  37. dvt/artifacts/schemas/catalog/__init__.py +12 -0
  38. dvt/artifacts/schemas/catalog/v1/__init__.py +0 -0
  39. dvt/artifacts/schemas/catalog/v1/catalog.py +60 -0
  40. dvt/artifacts/schemas/freshness/__init__.py +1 -0
  41. dvt/artifacts/schemas/freshness/v3/__init__.py +0 -0
  42. dvt/artifacts/schemas/freshness/v3/freshness.py +159 -0
  43. dvt/artifacts/schemas/manifest/__init__.py +2 -0
  44. dvt/artifacts/schemas/manifest/v12/__init__.py +0 -0
  45. dvt/artifacts/schemas/manifest/v12/manifest.py +212 -0
  46. dvt/artifacts/schemas/results.py +148 -0
  47. dvt/artifacts/schemas/run/__init__.py +2 -0
  48. dvt/artifacts/schemas/run/v5/__init__.py +0 -0
  49. dvt/artifacts/schemas/run/v5/run.py +184 -0
  50. dvt/artifacts/schemas/upgrades/__init__.py +4 -0
  51. dvt/artifacts/schemas/upgrades/upgrade_manifest.py +174 -0
  52. dvt/artifacts/schemas/upgrades/upgrade_manifest_dbt_version.py +2 -0
  53. dvt/artifacts/utils/validation.py +153 -0
  54. dvt/cli/__init__.py +1 -0
  55. dvt/cli/context.py +16 -0
  56. dvt/cli/exceptions.py +56 -0
  57. dvt/cli/flags.py +558 -0
  58. dvt/cli/main.py +971 -0
  59. dvt/cli/option_types.py +121 -0
  60. dvt/cli/options.py +79 -0
  61. dvt/cli/params.py +803 -0
  62. dvt/cli/requires.py +478 -0
  63. dvt/cli/resolvers.py +32 -0
  64. dvt/cli/types.py +40 -0
  65. dvt/clients/__init__.py +0 -0
  66. dvt/clients/checked_load.py +82 -0
  67. dvt/clients/git.py +164 -0
  68. dvt/clients/jinja.py +206 -0
  69. dvt/clients/jinja_static.py +245 -0
  70. dvt/clients/registry.py +192 -0
  71. dvt/clients/yaml_helper.py +68 -0
  72. dvt/compilation.py +833 -0
  73. dvt/compute/__init__.py +26 -0
  74. dvt/compute/base.py +288 -0
  75. dvt/compute/engines/__init__.py +13 -0
  76. dvt/compute/engines/duckdb_engine.py +368 -0
  77. dvt/compute/engines/spark_engine.py +273 -0
  78. dvt/compute/query_analyzer.py +212 -0
  79. dvt/compute/router.py +483 -0
  80. dvt/config/__init__.py +4 -0
  81. dvt/config/catalogs.py +95 -0
  82. dvt/config/compute_config.py +406 -0
  83. dvt/config/profile.py +411 -0
  84. dvt/config/profiles_v2.py +464 -0
  85. dvt/config/project.py +893 -0
  86. dvt/config/renderer.py +232 -0
  87. dvt/config/runtime.py +491 -0
  88. dvt/config/selectors.py +209 -0
  89. dvt/config/utils.py +78 -0
  90. dvt/connectors/.gitignore +6 -0
  91. dvt/connectors/README.md +306 -0
  92. dvt/connectors/catalog.yml +217 -0
  93. dvt/connectors/download_connectors.py +300 -0
  94. dvt/constants.py +29 -0
  95. dvt/context/__init__.py +0 -0
  96. dvt/context/base.py +746 -0
  97. dvt/context/configured.py +136 -0
  98. dvt/context/context_config.py +350 -0
  99. dvt/context/docs.py +82 -0
  100. dvt/context/exceptions_jinja.py +179 -0
  101. dvt/context/macro_resolver.py +195 -0
  102. dvt/context/macros.py +171 -0
  103. dvt/context/manifest.py +73 -0
  104. dvt/context/providers.py +2198 -0
  105. dvt/context/query_header.py +14 -0
  106. dvt/context/secret.py +59 -0
  107. dvt/context/target.py +74 -0
  108. dvt/contracts/__init__.py +0 -0
  109. dvt/contracts/files.py +413 -0
  110. dvt/contracts/graph/__init__.py +0 -0
  111. dvt/contracts/graph/manifest.py +1904 -0
  112. dvt/contracts/graph/metrics.py +98 -0
  113. dvt/contracts/graph/model_config.py +71 -0
  114. dvt/contracts/graph/node_args.py +42 -0
  115. dvt/contracts/graph/nodes.py +1806 -0
  116. dvt/contracts/graph/semantic_manifest.py +233 -0
  117. dvt/contracts/graph/unparsed.py +812 -0
  118. dvt/contracts/project.py +417 -0
  119. dvt/contracts/results.py +53 -0
  120. dvt/contracts/selection.py +23 -0
  121. dvt/contracts/sql.py +86 -0
  122. dvt/contracts/state.py +69 -0
  123. dvt/contracts/util.py +46 -0
  124. dvt/deprecations.py +347 -0
  125. dvt/deps/__init__.py +0 -0
  126. dvt/deps/base.py +153 -0
  127. dvt/deps/git.py +196 -0
  128. dvt/deps/local.py +80 -0
  129. dvt/deps/registry.py +131 -0
  130. dvt/deps/resolver.py +149 -0
  131. dvt/deps/tarball.py +121 -0
  132. dvt/docs/source/_ext/dbt_click.py +118 -0
  133. dvt/docs/source/conf.py +32 -0
  134. dvt/env_vars.py +64 -0
  135. dvt/event_time/event_time.py +40 -0
  136. dvt/event_time/sample_window.py +60 -0
  137. dvt/events/__init__.py +16 -0
  138. dvt/events/base_types.py +37 -0
  139. dvt/events/core_types_pb2.py +2 -0
  140. dvt/events/logging.py +109 -0
  141. dvt/events/types.py +2534 -0
  142. dvt/exceptions.py +1487 -0
  143. dvt/flags.py +89 -0
  144. dvt/graph/__init__.py +11 -0
  145. dvt/graph/cli.py +248 -0
  146. dvt/graph/graph.py +172 -0
  147. dvt/graph/queue.py +213 -0
  148. dvt/graph/selector.py +375 -0
  149. dvt/graph/selector_methods.py +976 -0
  150. dvt/graph/selector_spec.py +223 -0
  151. dvt/graph/thread_pool.py +18 -0
  152. dvt/hooks.py +21 -0
  153. dvt/include/README.md +49 -0
  154. dvt/include/__init__.py +3 -0
  155. dvt/include/global_project.py +4 -0
  156. dvt/include/starter_project/.gitignore +4 -0
  157. dvt/include/starter_project/README.md +15 -0
  158. dvt/include/starter_project/__init__.py +3 -0
  159. dvt/include/starter_project/analyses/.gitkeep +0 -0
  160. dvt/include/starter_project/dvt_project.yml +36 -0
  161. dvt/include/starter_project/macros/.gitkeep +0 -0
  162. dvt/include/starter_project/models/example/my_first_dbt_model.sql +27 -0
  163. dvt/include/starter_project/models/example/my_second_dbt_model.sql +6 -0
  164. dvt/include/starter_project/models/example/schema.yml +21 -0
  165. dvt/include/starter_project/seeds/.gitkeep +0 -0
  166. dvt/include/starter_project/snapshots/.gitkeep +0 -0
  167. dvt/include/starter_project/tests/.gitkeep +0 -0
  168. dvt/internal_deprecations.py +27 -0
  169. dvt/jsonschemas/__init__.py +3 -0
  170. dvt/jsonschemas/jsonschemas.py +309 -0
  171. dvt/jsonschemas/project/0.0.110.json +4717 -0
  172. dvt/jsonschemas/project/0.0.85.json +2015 -0
  173. dvt/jsonschemas/resources/0.0.110.json +2636 -0
  174. dvt/jsonschemas/resources/0.0.85.json +2536 -0
  175. dvt/jsonschemas/resources/latest.json +6773 -0
  176. dvt/links.py +4 -0
  177. dvt/materializations/__init__.py +0 -0
  178. dvt/materializations/incremental/__init__.py +0 -0
  179. dvt/materializations/incremental/microbatch.py +235 -0
  180. dvt/mp_context.py +8 -0
  181. dvt/node_types.py +37 -0
  182. dvt/parser/__init__.py +23 -0
  183. dvt/parser/analysis.py +21 -0
  184. dvt/parser/base.py +549 -0
  185. dvt/parser/common.py +267 -0
  186. dvt/parser/docs.py +52 -0
  187. dvt/parser/fixtures.py +51 -0
  188. dvt/parser/functions.py +30 -0
  189. dvt/parser/generic_test.py +100 -0
  190. dvt/parser/generic_test_builders.py +334 -0
  191. dvt/parser/hooks.py +119 -0
  192. dvt/parser/macros.py +137 -0
  193. dvt/parser/manifest.py +2204 -0
  194. dvt/parser/models.py +574 -0
  195. dvt/parser/partial.py +1179 -0
  196. dvt/parser/read_files.py +445 -0
  197. dvt/parser/schema_generic_tests.py +423 -0
  198. dvt/parser/schema_renderer.py +111 -0
  199. dvt/parser/schema_yaml_readers.py +936 -0
  200. dvt/parser/schemas.py +1467 -0
  201. dvt/parser/search.py +149 -0
  202. dvt/parser/seeds.py +28 -0
  203. dvt/parser/singular_test.py +20 -0
  204. dvt/parser/snapshots.py +44 -0
  205. dvt/parser/sources.py +557 -0
  206. dvt/parser/sql.py +63 -0
  207. dvt/parser/unit_tests.py +622 -0
  208. dvt/plugins/__init__.py +20 -0
  209. dvt/plugins/contracts.py +10 -0
  210. dvt/plugins/exceptions.py +2 -0
  211. dvt/plugins/manager.py +164 -0
  212. dvt/plugins/manifest.py +21 -0
  213. dvt/profiler.py +20 -0
  214. dvt/py.typed +1 -0
  215. dvt/runners/__init__.py +2 -0
  216. dvt/runners/exposure_runner.py +7 -0
  217. dvt/runners/no_op_runner.py +46 -0
  218. dvt/runners/saved_query_runner.py +7 -0
  219. dvt/selected_resources.py +8 -0
  220. dvt/task/__init__.py +0 -0
  221. dvt/task/base.py +504 -0
  222. dvt/task/build.py +197 -0
  223. dvt/task/clean.py +57 -0
  224. dvt/task/clone.py +162 -0
  225. dvt/task/compile.py +151 -0
  226. dvt/task/compute.py +366 -0
  227. dvt/task/debug.py +650 -0
  228. dvt/task/deps.py +280 -0
  229. dvt/task/docs/__init__.py +3 -0
  230. dvt/task/docs/generate.py +408 -0
  231. dvt/task/docs/index.html +250 -0
  232. dvt/task/docs/serve.py +28 -0
  233. dvt/task/freshness.py +323 -0
  234. dvt/task/function.py +122 -0
  235. dvt/task/group_lookup.py +46 -0
  236. dvt/task/init.py +374 -0
  237. dvt/task/list.py +237 -0
  238. dvt/task/printer.py +176 -0
  239. dvt/task/profiles.py +256 -0
  240. dvt/task/retry.py +175 -0
  241. dvt/task/run.py +1146 -0
  242. dvt/task/run_operation.py +142 -0
  243. dvt/task/runnable.py +802 -0
  244. dvt/task/seed.py +104 -0
  245. dvt/task/show.py +150 -0
  246. dvt/task/snapshot.py +57 -0
  247. dvt/task/sql.py +111 -0
  248. dvt/task/test.py +464 -0
  249. dvt/tests/fixtures/__init__.py +1 -0
  250. dvt/tests/fixtures/project.py +620 -0
  251. dvt/tests/util.py +651 -0
  252. dvt/tracking.py +529 -0
  253. dvt/utils/__init__.py +3 -0
  254. dvt/utils/artifact_upload.py +151 -0
  255. dvt/utils/utils.py +408 -0
  256. dvt/version.py +249 -0
  257. dvt_core-1.11.0b4.dist-info/METADATA +252 -0
  258. dvt_core-1.11.0b4.dist-info/RECORD +261 -0
  259. dvt_core-1.11.0b4.dist-info/WHEEL +5 -0
  260. dvt_core-1.11.0b4.dist-info/entry_points.txt +2 -0
  261. dvt_core-1.11.0b4.dist-info/top_level.txt +1 -0
@@ -0,0 +1,148 @@
1
+ from dataclasses import dataclass
2
+ from datetime import datetime, timezone
3
+ from typing import Any, Callable, Dict, List, Optional, Sequence, Union
4
+
5
+ from dvt.contracts.graph.nodes import ResultNode
6
+
7
+ from dbt_common.dataclass_schema import StrEnum, dbtClassMixin
8
+ from dbt_common.events.helpers import datetime_to_json_string
9
+ from dbt_common.utils import cast_to_int, cast_to_str
10
+
11
+
12
+ @dataclass
13
+ class TimingInfo(dbtClassMixin):
14
+ """
15
+ Represents a step in the execution of a node.
16
+ `name` should be one of: compile, execute, or other
17
+ Do not call directly, use `collect_timing_info` instead.
18
+ """
19
+
20
+ name: str
21
+ started_at: Optional[datetime] = None
22
+ completed_at: Optional[datetime] = None
23
+
24
+ def begin(self):
25
+ self.started_at = datetime.now(timezone.utc).replace(tzinfo=None)
26
+
27
+ def end(self):
28
+ self.completed_at = datetime.now(timezone.utc).replace(tzinfo=None)
29
+
30
+ def to_msg_dict(self):
31
+ msg_dict = {"name": str(self.name)}
32
+ if self.started_at:
33
+ msg_dict["started_at"] = datetime_to_json_string(self.started_at)
34
+ if self.completed_at:
35
+ msg_dict["completed_at"] = datetime_to_json_string(self.completed_at)
36
+ return msg_dict
37
+
38
+
39
+ # This is a context manager
40
+ class collect_timing_info:
41
+ def __init__(self, name: str, callback: Callable[[TimingInfo], None]) -> None:
42
+ self.timing_info = TimingInfo(name=name)
43
+ self.callback = callback
44
+
45
+ def __enter__(self):
46
+ self.timing_info.begin()
47
+
48
+ def __exit__(self, exc_type, exc_value, traceback):
49
+ self.timing_info.end()
50
+ self.callback(self.timing_info)
51
+
52
+
53
+ class RunningStatus(StrEnum):
54
+ Started = "started"
55
+ Compiling = "compiling"
56
+ Executing = "executing"
57
+
58
+
59
+ class NodeStatus(StrEnum):
60
+ Success = "success"
61
+ Error = "error"
62
+ Fail = "fail"
63
+ Warn = "warn"
64
+ Skipped = "skipped"
65
+ PartialSuccess = "partial success"
66
+ Pass = "pass"
67
+ RuntimeErr = "runtime error"
68
+ NoOp = "no-op"
69
+
70
+
71
+ class RunStatus(StrEnum):
72
+ Success = NodeStatus.Success
73
+ Error = NodeStatus.Error
74
+ Skipped = NodeStatus.Skipped
75
+ PartialSuccess = NodeStatus.PartialSuccess
76
+ NoOp = NodeStatus.NoOp
77
+
78
+
79
+ class TestStatus(StrEnum):
80
+ __test__ = False
81
+ Pass = NodeStatus.Pass
82
+ Error = NodeStatus.Error
83
+ Fail = NodeStatus.Fail
84
+ Warn = NodeStatus.Warn
85
+ Skipped = NodeStatus.Skipped
86
+
87
+
88
+ class FreshnessStatus(StrEnum):
89
+ Pass = NodeStatus.Pass
90
+ Warn = NodeStatus.Warn
91
+ Error = NodeStatus.Error
92
+ RuntimeErr = NodeStatus.RuntimeErr
93
+
94
+
95
+ @dataclass
96
+ class BaseResult(dbtClassMixin):
97
+ status: Union[RunStatus, TestStatus, FreshnessStatus]
98
+ timing: List[TimingInfo]
99
+ thread_id: str
100
+ execution_time: float
101
+ adapter_response: Dict[str, Any]
102
+ message: Optional[str]
103
+ failures: Optional[int]
104
+
105
+ @classmethod
106
+ def __pre_deserialize__(cls, data):
107
+ data = super().__pre_deserialize__(data)
108
+ if "message" not in data:
109
+ data["message"] = None
110
+ if "failures" not in data:
111
+ data["failures"] = None
112
+ return data
113
+
114
+ def to_msg_dict(self):
115
+ msg_dict = {
116
+ "status": str(self.status),
117
+ "message": cast_to_str(self.message),
118
+ "thread": self.thread_id,
119
+ "execution_time": self.execution_time,
120
+ "num_failures": cast_to_int(self.failures),
121
+ "timing_info": [ti.to_msg_dict() for ti in self.timing],
122
+ "adapter_response": self.adapter_response,
123
+ }
124
+ return msg_dict
125
+
126
+
127
+ @dataclass
128
+ class NodeResult(BaseResult):
129
+ node: ResultNode
130
+
131
+
132
+ @dataclass
133
+ class ExecutionResult(dbtClassMixin):
134
+ results: Sequence[BaseResult]
135
+ elapsed_time: float
136
+
137
+ def __len__(self):
138
+ return len(self.results)
139
+
140
+ def __iter__(self):
141
+ return iter(self.results)
142
+
143
+ def __getitem__(self, idx):
144
+ return self.results[idx]
145
+
146
+
147
+ # due to issues with typing.Union collapsing subclasses, this can't subclass
148
+ # PartialResult
@@ -0,0 +1,2 @@
1
+ # alias to latest
2
+ from dvt.artifacts.schemas.run.v5.run import * # noqa
File without changes
@@ -0,0 +1,184 @@
1
+ from __future__ import annotations
2
+
3
+ import copy
4
+ import threading
5
+ from dataclasses import dataclass, field
6
+ from datetime import datetime, timezone
7
+ from typing import Any, Dict, Iterable, Optional, Sequence, Tuple
8
+
9
+ # https://github.com/dbt-labs/dbt-core/issues/10098
10
+ # Needed for Mashumaro serialization of RunResult below
11
+ # TODO: investigate alternative approaches to restore conditional import
12
+ # if TYPE_CHECKING:
13
+ import agate
14
+ from dvt.artifacts.resources import CompiledResource
15
+ from dvt.artifacts.schemas.base import (
16
+ ArtifactMixin,
17
+ BaseArtifactMetadata,
18
+ get_artifact_schema_version,
19
+ schema_version,
20
+ )
21
+ from dvt.artifacts.schemas.batch_results import BatchResults
22
+ from dvt.artifacts.schemas.results import (
23
+ BaseResult,
24
+ ExecutionResult,
25
+ NodeResult,
26
+ ResultNode,
27
+ RunStatus,
28
+ )
29
+ from dvt.exceptions import scrub_secrets
30
+
31
+ from dbt_common.clients.system import write_json
32
+ from dbt_common.constants import SECRET_ENV_PREFIX
33
+
34
+
35
+ @dataclass
36
+ class RunResult(NodeResult):
37
+ agate_table: Optional["agate.Table"] = field(
38
+ default=None, metadata={"serialize": lambda x: None, "deserialize": lambda x: None}
39
+ )
40
+ batch_results: Optional[BatchResults] = None
41
+
42
+ @property
43
+ def skipped(self):
44
+ return self.status == RunStatus.Skipped
45
+
46
+ @classmethod
47
+ def from_node(cls, node: ResultNode, status: RunStatus, message: Optional[str]):
48
+ thread_id = threading.current_thread().name
49
+ return RunResult(
50
+ status=status,
51
+ thread_id=thread_id,
52
+ execution_time=0,
53
+ timing=[],
54
+ message=message,
55
+ node=node,
56
+ adapter_response={},
57
+ failures=None,
58
+ batch_results=None,
59
+ )
60
+
61
+
62
+ @dataclass
63
+ class RunResultsMetadata(BaseArtifactMetadata):
64
+ dbt_schema_version: str = field(
65
+ default_factory=lambda: str(RunResultsArtifact.dbt_schema_version)
66
+ )
67
+
68
+
69
+ @dataclass
70
+ class RunResultOutput(BaseResult):
71
+ unique_id: str
72
+ compiled: Optional[bool]
73
+ compiled_code: Optional[str]
74
+ relation_name: Optional[str]
75
+ batch_results: Optional[BatchResults] = None
76
+
77
+
78
+ def process_run_result(result: RunResult) -> RunResultOutput:
79
+
80
+ compiled = isinstance(result.node, CompiledResource)
81
+
82
+ return RunResultOutput(
83
+ unique_id=result.node.unique_id,
84
+ status=result.status,
85
+ timing=result.timing,
86
+ thread_id=result.thread_id,
87
+ execution_time=result.execution_time,
88
+ message=result.message,
89
+ adapter_response=result.adapter_response,
90
+ failures=result.failures,
91
+ batch_results=result.batch_results,
92
+ compiled=result.node.compiled if compiled else None, # type:ignore
93
+ compiled_code=result.node.compiled_code if compiled else None, # type:ignore
94
+ relation_name=result.node.relation_name if compiled else None, # type:ignore
95
+ )
96
+
97
+
98
+ @dataclass
99
+ class RunExecutionResult(
100
+ ExecutionResult,
101
+ ):
102
+ results: Sequence[RunResult]
103
+ args: Dict[str, Any] = field(default_factory=dict)
104
+ generated_at: datetime = field(
105
+ default_factory=lambda: datetime.now(timezone.utc).replace(tzinfo=None)
106
+ )
107
+
108
+ def write(self, path: str):
109
+ writable = RunResultsArtifact.from_execution_results(
110
+ results=self.results,
111
+ elapsed_time=self.elapsed_time,
112
+ generated_at=self.generated_at,
113
+ args=self.args,
114
+ )
115
+ writable.write(path)
116
+
117
+
118
+ @dataclass
119
+ @schema_version("run-results", 6)
120
+ class RunResultsArtifact(ExecutionResult, ArtifactMixin):
121
+ results: Sequence[RunResultOutput]
122
+ args: Dict[str, Any] = field(default_factory=dict)
123
+
124
+ @classmethod
125
+ def from_execution_results(
126
+ cls,
127
+ results: Sequence[RunResult],
128
+ elapsed_time: float,
129
+ generated_at: datetime,
130
+ args: Dict,
131
+ ):
132
+ processed_results = [
133
+ process_run_result(result) for result in results if isinstance(result, RunResult)
134
+ ]
135
+ meta = RunResultsMetadata(
136
+ dbt_schema_version=str(cls.dbt_schema_version),
137
+ generated_at=generated_at,
138
+ )
139
+
140
+ secret_vars = [
141
+ v for k, v in args["vars"].items() if k.startswith(SECRET_ENV_PREFIX) and v.strip()
142
+ ]
143
+
144
+ scrubbed_args = copy.deepcopy(args)
145
+
146
+ # scrub secrets in invocation command
147
+ scrubbed_args["invocation_command"] = scrub_secrets(
148
+ scrubbed_args["invocation_command"], secret_vars
149
+ )
150
+
151
+ # scrub secrets in vars dict
152
+ scrubbed_args["vars"] = {
153
+ k: scrub_secrets(v, secret_vars) for k, v in scrubbed_args["vars"].items()
154
+ }
155
+
156
+ return cls(
157
+ metadata=meta, results=processed_results, elapsed_time=elapsed_time, args=scrubbed_args
158
+ )
159
+
160
+ @classmethod
161
+ def compatible_previous_versions(cls) -> Iterable[Tuple[str, int]]:
162
+ return [
163
+ ("run-results", 4),
164
+ ("run-results", 5),
165
+ ]
166
+
167
+ @classmethod
168
+ def upgrade_schema_version(cls, data):
169
+ """This overrides the "upgrade_schema_version" call in VersionedSchema (via
170
+ ArtifactMixin) to modify the dictionary passed in from earlier versions of the run_results.
171
+ """
172
+ run_results_schema_version = get_artifact_schema_version(data)
173
+ # If less than the current version (v5), preprocess contents to match latest schema version
174
+ if run_results_schema_version <= 5:
175
+ # In v5, we added 'compiled' attributes to each result entry
176
+ # Going forward, dbt expects these to be populated
177
+ for result in data["results"]:
178
+ result["compiled"] = False
179
+ result["compiled_code"] = ""
180
+ result["relation_name"] = ""
181
+ return cls.from_dict(data)
182
+
183
+ def write(self, path: str):
184
+ write_json(path, self.to_dict(omit_none=False))
@@ -0,0 +1,4 @@
1
+ from dvt.artifacts.schemas.upgrades.upgrade_manifest import upgrade_manifest_json
2
+ from dvt.artifacts.schemas.upgrades.upgrade_manifest_dbt_version import (
3
+ upgrade_manifest_json_dbt_version,
4
+ )
@@ -0,0 +1,174 @@
1
+ def rename_sql_attr(node_content: dict) -> dict:
2
+ if "raw_sql" in node_content:
3
+ node_content["raw_code"] = node_content.pop("raw_sql")
4
+ if "compiled_sql" in node_content:
5
+ node_content["compiled_code"] = node_content.pop("compiled_sql")
6
+ node_content["language"] = "sql"
7
+ return node_content
8
+
9
+
10
+ def upgrade_ref_content(node_content: dict) -> dict:
11
+ # In v1.5 we switched Node.refs from List[List[str]] to List[Dict[str, Union[NodeVersion, str]]]
12
+ # Previous versions did not have a version keyword argument for ref
13
+ if "refs" in node_content:
14
+ upgraded_refs = []
15
+ for ref in node_content["refs"]:
16
+ if isinstance(ref, list):
17
+ if len(ref) == 1:
18
+ upgraded_refs.append({"package": None, "name": ref[0], "version": None})
19
+ else:
20
+ upgraded_refs.append({"package": ref[0], "name": ref[1], "version": None})
21
+ node_content["refs"] = upgraded_refs
22
+ return node_content
23
+
24
+
25
+ def upgrade_node_content(node_content):
26
+ rename_sql_attr(node_content)
27
+ upgrade_ref_content(node_content)
28
+ if node_content["resource_type"] != "seed" and "root_path" in node_content:
29
+ del node_content["root_path"]
30
+
31
+
32
+ def upgrade_seed_content(node_content):
33
+ # Remove compilation related attributes
34
+ for attr_name in (
35
+ "language",
36
+ "refs",
37
+ "sources",
38
+ "metrics",
39
+ "compiled_path",
40
+ "compiled",
41
+ "compiled_code",
42
+ "extra_ctes_injected",
43
+ "extra_ctes",
44
+ "relation_name",
45
+ ):
46
+ if attr_name in node_content:
47
+ del node_content[attr_name]
48
+ # In v1.4, we switched SeedNode.depends_on from DependsOn to MacroDependsOn
49
+ node_content.get("depends_on", {}).pop("nodes", None)
50
+
51
+
52
+ def drop_v9_and_prior_metrics(manifest: dict) -> None:
53
+ manifest["metrics"] = {}
54
+ filtered_disabled_entries = {}
55
+ for entry_name, resource_list in manifest.get("disabled", {}).items():
56
+ filtered_resource_list = []
57
+ for resource in resource_list:
58
+ if resource.get("resource_type") != "metric":
59
+ filtered_resource_list.append(resource)
60
+ filtered_disabled_entries[entry_name] = filtered_resource_list
61
+
62
+ manifest["disabled"] = filtered_disabled_entries
63
+
64
+
65
+ def _convert_dct_with_filter(v10_dct_with_opt_filter):
66
+ """Upgrage the filter object from v10 to v11.
67
+
68
+ v10 filters from a serialized manifest looked like:
69
+ {..., 'filter': {'where_sql_template': '<filter_value>'}}
70
+ whereas v11 filters look like:
71
+ {..., 'filter': {'where_filters': [{'where_sql_template': '<filter_value>'}, ...]}}
72
+ """
73
+ if v10_dct_with_opt_filter is not None and v10_dct_with_opt_filter.get("filter") is not None:
74
+ v10_dct_with_opt_filter["filter"] = {"where_filters": [v10_dct_with_opt_filter["filter"]]}
75
+
76
+
77
+ def _convert_metric(v10_metric_dict):
78
+ """Upgrades a v10 metric object to a v11 metric object.
79
+
80
+ Specifcally the following properties change
81
+ 1. metric.filter
82
+ 2. metric.type_params.measure.filter
83
+ 3. metric.type_params.input_measures[x].filter
84
+ 4. metric.type_params.numerator.filter
85
+ 5. metric.type_params.denominator.filter
86
+ 6. metric.type_params.metrics[x].filter"
87
+ """
88
+
89
+ # handles top level metric filter
90
+ _convert_dct_with_filter(v10_metric_dict)
91
+
92
+ type_params = v10_metric_dict.get("type_params")
93
+ if type_params is not None:
94
+ _convert_dct_with_filter(type_params.get("measure"))
95
+ _convert_dct_with_filter(type_params.get("numerator"))
96
+ _convert_dct_with_filter(type_params.get("denominator"))
97
+
98
+ # handles metric.type_params.input_measures[x].filter
99
+ input_measures = type_params.get("input_measures")
100
+ if input_measures is not None:
101
+ for input_measure in input_measures:
102
+ _convert_dct_with_filter(input_measure)
103
+
104
+ # handles metric.type_params.metrics[x].filter
105
+ metrics = type_params.get("metrics")
106
+ if metrics is not None:
107
+ for metric in metrics:
108
+ _convert_dct_with_filter(metric)
109
+
110
+
111
+ def upgrade_v10_metric_filters(manifest: dict):
112
+ """Handles metric filters changes from v10 to v11."""
113
+
114
+ metrics = manifest.get("metrics", {})
115
+ for metric in metrics.values():
116
+ _convert_metric(metric)
117
+
118
+ disabled_nodes = manifest.get("disabled", {})
119
+ for unique_id, nodes in disabled_nodes.items():
120
+ if unique_id.split(".")[0] == "metric":
121
+ for node in nodes:
122
+ _convert_metric(node)
123
+
124
+
125
+ def upgrade_manifest_json(manifest: dict, manifest_schema_version: int) -> dict:
126
+ # this should remain 9 while the check in `upgrade_schema_version` may change
127
+ if manifest_schema_version <= 9:
128
+ drop_v9_and_prior_metrics(manifest=manifest)
129
+ elif manifest_schema_version == 10:
130
+ upgrade_v10_metric_filters(manifest=manifest)
131
+
132
+ for node_content in manifest.get("nodes", {}).values():
133
+ upgrade_node_content(node_content)
134
+ if node_content["resource_type"] == "seed":
135
+ upgrade_seed_content(node_content)
136
+ for disabled in manifest.get("disabled", {}).values():
137
+ # There can be multiple disabled nodes for the same unique_id
138
+ # so make sure all the nodes get the attr renamed
139
+ for node_content in disabled:
140
+ upgrade_node_content(node_content)
141
+ if node_content["resource_type"] == "seed":
142
+ upgrade_seed_content(node_content)
143
+ # add group key
144
+ if "groups" not in manifest:
145
+ manifest["groups"] = {}
146
+ if "group_map" not in manifest:
147
+ manifest["group_map"] = {}
148
+ # add unit_tests key
149
+ if "unit_tests" not in manifest:
150
+ manifest["unit_tests"] = {}
151
+ for metric_content in manifest.get("metrics", {}).values():
152
+ # handle attr renames + value translation ("expression" -> "derived")
153
+ metric_content = upgrade_ref_content(metric_content)
154
+ if "root_path" in metric_content:
155
+ del metric_content["root_path"]
156
+ for exposure_content in manifest.get("exposures", {}).values():
157
+ exposure_content = upgrade_ref_content(exposure_content)
158
+ if "root_path" in exposure_content:
159
+ del exposure_content["root_path"]
160
+ for source_content in manifest.get("sources", {}).values():
161
+ if "root_path" in source_content:
162
+ del source_content["root_path"]
163
+ for macro_content in manifest.get("macros", {}).values():
164
+ if "root_path" in macro_content:
165
+ del macro_content["root_path"]
166
+ for doc_content in manifest.get("docs", {}).values():
167
+ if "root_path" in doc_content:
168
+ del doc_content["root_path"]
169
+ doc_content["resource_type"] = "doc"
170
+ if "semantic_models" not in manifest:
171
+ manifest["semantic_models"] = {}
172
+ if "saved_queries" not in manifest:
173
+ manifest["saved_queries"] = {}
174
+ return manifest
@@ -0,0 +1,2 @@
1
+ def upgrade_manifest_json_dbt_version(manifest: dict) -> dict:
2
+ return manifest
@@ -0,0 +1,153 @@
1
+ import re
2
+
3
+ HTML_COLORS = [
4
+ "aliceblue",
5
+ "antiquewhite",
6
+ "aqua",
7
+ "aquamarine",
8
+ "azure",
9
+ "beige",
10
+ "bisque",
11
+ "black",
12
+ "blanchedalmond",
13
+ "blue",
14
+ "blueviolet",
15
+ "brown",
16
+ "burlywood",
17
+ "cadetblue",
18
+ "chartreuse",
19
+ "chocolate",
20
+ "coral",
21
+ "cornflowerblue",
22
+ "cornsilk",
23
+ "crimson",
24
+ "cyan",
25
+ "darkblue",
26
+ "darkcyan",
27
+ "darkgoldenrod",
28
+ "darkgray",
29
+ "darkgreen",
30
+ "darkkhaki",
31
+ "darkmagenta",
32
+ "darkolivegreen",
33
+ "darkorange",
34
+ "darkorchid",
35
+ "darkred",
36
+ "darksalmon",
37
+ "darkseagreen",
38
+ "darkslateblue",
39
+ "darkslategray",
40
+ "darkturquoise",
41
+ "darkviolet",
42
+ "deeppink",
43
+ "deepskyblue",
44
+ "dimgray",
45
+ "dodgerblue",
46
+ "firebrick",
47
+ "floralwhite",
48
+ "forestgreen",
49
+ "fuchsia",
50
+ "gainsboro",
51
+ "ghostwhite",
52
+ "gold",
53
+ "goldenrod",
54
+ "gray",
55
+ "green",
56
+ "greenyellow",
57
+ "honeydew",
58
+ "hotpink",
59
+ "indianred",
60
+ "indigo",
61
+ "ivory",
62
+ "khaki",
63
+ "lavender",
64
+ "lavenderblush",
65
+ "lawngreen",
66
+ "lemonchiffon",
67
+ "lightblue",
68
+ "lightcoral",
69
+ "lightcyan",
70
+ "lightgoldenrodyellow",
71
+ "lightgray",
72
+ "lightgreen",
73
+ "lightpink",
74
+ "lightsalmon",
75
+ "lightsalmon",
76
+ "lightseagreen",
77
+ "lightskyblue",
78
+ "lightslategray",
79
+ "lightsteelblue",
80
+ "lightyellow",
81
+ "lime",
82
+ "limegreen",
83
+ "linen",
84
+ "magenta",
85
+ "maroon",
86
+ "mediumaquamarine",
87
+ "mediumblue",
88
+ "mediumorchid",
89
+ "mediumpurple",
90
+ "mediumseagreen",
91
+ "mediumslateblue",
92
+ "mediumslateblue",
93
+ "mediumspringgreen",
94
+ "mediumturquoise",
95
+ "mediumvioletred",
96
+ "midnightblue",
97
+ "mintcream",
98
+ "mistyrose",
99
+ "moccasin",
100
+ "navajowhite",
101
+ "navy",
102
+ "oldlace",
103
+ "olive",
104
+ "olivedrab",
105
+ "orange",
106
+ "orangered",
107
+ "orchid",
108
+ "palegoldenrod",
109
+ "palegreen",
110
+ "paleturquoise",
111
+ "palevioletred",
112
+ "papayawhip",
113
+ "peachpuff",
114
+ "peru",
115
+ "pink",
116
+ "plum",
117
+ "powderblue",
118
+ "purple",
119
+ "rebeccapurple",
120
+ "red",
121
+ "rosybrown",
122
+ "royalblue",
123
+ "saddlebrown",
124
+ "salmon",
125
+ "sandybrown",
126
+ "seagreen",
127
+ "seashell",
128
+ "sienna",
129
+ "silver",
130
+ "skyblue",
131
+ "slateblue",
132
+ "slategray",
133
+ "snow",
134
+ "springgreen",
135
+ "steelblue",
136
+ "tan",
137
+ "teal",
138
+ "thistle",
139
+ "tomato",
140
+ "turquoise",
141
+ "violet",
142
+ "wheat",
143
+ "white",
144
+ "whitesmoke",
145
+ "yellow",
146
+ "yellowgreen",
147
+ ]
148
+
149
+
150
+ def validate_color(color: str) -> bool:
151
+ match_hex = re.search(r"^#(?:[0-9a-f]{3}){1,2}$", color.lower())
152
+ match_html_color_name = color.lower() in HTML_COLORS
153
+ return bool(match_hex or match_html_color_name)
dvt/cli/__init__.py ADDED
@@ -0,0 +1 @@
1
+ from .main import cli as dbt_cli # noqa
dvt/cli/context.py ADDED
@@ -0,0 +1,16 @@
1
+ from typing import Optional
2
+
3
+ import click
4
+ from dvt.cli.main import cli as dbt
5
+
6
+
7
+ def make_context(args, command=dbt) -> Optional[click.Context]:
8
+ try:
9
+ ctx = command.make_context(command.name, args)
10
+ except click.exceptions.Exit:
11
+ return None
12
+
13
+ ctx.invoked_subcommand = ctx.protected_args[0] if ctx.protected_args else None
14
+ ctx.obj = {}
15
+
16
+ return ctx