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
dvt/task/seed.py ADDED
@@ -0,0 +1,104 @@
1
+ import random
2
+ from typing import Optional, Type
3
+
4
+ from dvt.artifacts.schemas.results import NodeStatus, RunStatus
5
+ from dvt.contracts.graph.manifest import Manifest
6
+ from dvt.events.types import LogSeedResult, LogStartLine, SeedHeader
7
+ from dvt.graph import ResourceTypeSelector
8
+ from dvt.node_types import NodeType
9
+ from dvt.task import group_lookup
10
+ from dvt.task.base import BaseRunner
11
+ from dvt.task.printer import print_run_end_messages
12
+ from dvt.task.run import ModelRunner, RunTask
13
+
14
+ from dbt_common.events.base_types import EventLevel
15
+ from dbt_common.events.functions import fire_event
16
+ from dbt_common.events.types import Formatting
17
+ from dbt_common.exceptions import DbtInternalError
18
+
19
+
20
+ class SeedRunner(ModelRunner):
21
+ def describe_node(self) -> str:
22
+ return "seed file {}".format(self.get_node_representation())
23
+
24
+ def before_execute(self) -> None:
25
+ fire_event(
26
+ LogStartLine(
27
+ description=self.describe_node(),
28
+ index=self.node_index,
29
+ total=self.num_nodes,
30
+ node_info=self.node.node_info,
31
+ )
32
+ )
33
+
34
+ def _build_run_model_result(self, model, context):
35
+ result = super()._build_run_model_result(model, context)
36
+ agate_result = context["load_result"]("agate_table")
37
+ result.agate_table = agate_result.table
38
+ return result
39
+
40
+ def compile(self, manifest: Manifest):
41
+ return self.node
42
+
43
+ def print_result_line(self, result):
44
+ model = result.node
45
+ group = group_lookup.get(model.unique_id)
46
+ level = EventLevel.ERROR if result.status == NodeStatus.Error else EventLevel.INFO
47
+ fire_event(
48
+ LogSeedResult(
49
+ status=result.status,
50
+ result_message=result.message,
51
+ index=self.node_index,
52
+ total=self.num_nodes,
53
+ execution_time=result.execution_time,
54
+ schema=self.node.schema,
55
+ relation=model.alias,
56
+ node_info=model.node_info,
57
+ group=group,
58
+ ),
59
+ level=level,
60
+ )
61
+
62
+
63
+ class SeedTask(RunTask):
64
+ def raise_on_first_error(self) -> bool:
65
+ return False
66
+
67
+ def get_node_selector(self):
68
+ if self.manifest is None or self.graph is None:
69
+ raise DbtInternalError("manifest and graph must be set to get perform node selection")
70
+ return ResourceTypeSelector(
71
+ graph=self.graph,
72
+ manifest=self.manifest,
73
+ previous_state=self.previous_state,
74
+ resource_types=[NodeType.Seed],
75
+ )
76
+
77
+ def get_runner_type(self, _) -> Optional[Type[BaseRunner]]:
78
+ return SeedRunner
79
+
80
+ def task_end_messages(self, results) -> None:
81
+ if self.args.show:
82
+ self.show_tables(results)
83
+
84
+ print_run_end_messages(results)
85
+
86
+ def show_table(self, result):
87
+ table = result.agate_table
88
+ rand_table = table.order_by(lambda x: random.random())
89
+
90
+ schema = result.node.schema
91
+ alias = result.node.alias
92
+
93
+ header = "Random sample of table: {}.{}".format(schema, alias)
94
+ fire_event(Formatting(""))
95
+ fire_event(SeedHeader(header=header))
96
+ fire_event(Formatting("-" * len(header)))
97
+
98
+ rand_table.print_table(max_rows=10, max_columns=None)
99
+ fire_event(Formatting(""))
100
+
101
+ def show_tables(self, results):
102
+ for result in results:
103
+ if result.status != RunStatus.Error:
104
+ self.show_table(result)
dvt/task/show.py ADDED
@@ -0,0 +1,150 @@
1
+ import io
2
+ import threading
3
+ import time
4
+
5
+ from dvt.artifacts.schemas.run import RunResult, RunStatus
6
+ from dvt.context.providers import generate_runtime_model_context
7
+ from dvt.contracts.graph.nodes import SeedNode
8
+ from dvt.events.types import ShowNode
9
+ from dvt.flags import get_flags
10
+ from dvt.task.base import ConfiguredTask
11
+ from dvt.task.compile import CompileRunner, CompileTask
12
+ from dvt.task.seed import SeedRunner
13
+
14
+ from dbt.adapters.factory import get_adapter
15
+ from dbt_common.events.base_types import EventLevel
16
+ from dbt_common.events.functions import fire_event
17
+ from dbt_common.events.types import Note
18
+ from dbt_common.exceptions import DbtRuntimeError
19
+
20
+
21
+ class ShowRunner(CompileRunner):
22
+ def __init__(self, config, adapter, node, node_index, num_nodes) -> None:
23
+ super().__init__(config, adapter, node, node_index, num_nodes)
24
+ self.run_ephemeral_models = True
25
+
26
+ def execute(self, compiled_node, manifest):
27
+ start_time = time.time()
28
+
29
+ # Allow passing in -1 (or any negative number) to get all rows
30
+ limit = None if self.config.args.limit < 0 else self.config.args.limit
31
+
32
+ model_context = generate_runtime_model_context(compiled_node, self.config, manifest)
33
+ compiled_node.compiled_code = self.adapter.execute_macro(
34
+ macro_name="get_show_sql",
35
+ macro_resolver=manifest,
36
+ context_override=model_context,
37
+ kwargs={
38
+ "compiled_code": model_context["compiled_code"],
39
+ "sql_header": model_context["config"].get("sql_header"),
40
+ "limit": limit,
41
+ },
42
+ )
43
+ adapter_response, execute_result = self.adapter.execute(
44
+ compiled_node.compiled_code, fetch=True
45
+ )
46
+
47
+ end_time = time.time()
48
+
49
+ return RunResult(
50
+ node=compiled_node,
51
+ status=RunStatus.Success,
52
+ timing=[],
53
+ thread_id=threading.current_thread().name,
54
+ execution_time=end_time - start_time,
55
+ message=None,
56
+ adapter_response=adapter_response.to_dict(),
57
+ agate_table=execute_result,
58
+ failures=None,
59
+ batch_results=None,
60
+ )
61
+
62
+
63
+ class ShowTask(CompileTask):
64
+ def _runtime_initialize(self):
65
+ if not (self.args.select or getattr(self.args, "inline", None)):
66
+ raise DbtRuntimeError("Either --select or --inline must be passed to show")
67
+ super()._runtime_initialize()
68
+
69
+ def get_runner_type(self, node):
70
+ if isinstance(node, SeedNode):
71
+ return SeedRunner
72
+ else:
73
+ return ShowRunner
74
+
75
+ def task_end_messages(self, results) -> None:
76
+ is_inline = bool(getattr(self.args, "inline", None))
77
+
78
+ if is_inline:
79
+ matched_results = [result for result in results if result.node.name == "inline_query"]
80
+ else:
81
+ matched_results = []
82
+ for result in results:
83
+ if result.node.name in self.selection_arg[0]:
84
+ matched_results.append(result)
85
+ else:
86
+ fire_event(
87
+ Note(msg=f"Excluded node '{result.node.name}' from results"),
88
+ EventLevel.DEBUG,
89
+ )
90
+
91
+ for result in matched_results:
92
+ table = result.agate_table
93
+
94
+ # Hack to get Agate table output as string
95
+ output = io.StringIO()
96
+ if self.args.output == "json":
97
+ table.to_json(path=output)
98
+ else:
99
+ table.print_table(output=output, max_rows=None)
100
+
101
+ node_name = result.node.name
102
+
103
+ if hasattr(result.node, "version") and result.node.version:
104
+ node_name += f".v{result.node.version}"
105
+
106
+ fire_event(
107
+ ShowNode(
108
+ node_name=node_name,
109
+ preview=output.getvalue(),
110
+ is_inline=is_inline,
111
+ output_format=self.args.output,
112
+ unique_id=result.node.unique_id,
113
+ quiet=get_flags().QUIET,
114
+ )
115
+ )
116
+
117
+ def _handle_result(self, result) -> None:
118
+ super()._handle_result(result)
119
+
120
+ if (
121
+ result.node.is_ephemeral_model
122
+ and type(self) is ShowTask
123
+ and (self.args.select or getattr(self.args, "inline", None))
124
+ ):
125
+ self.node_results.append(result)
126
+
127
+
128
+ class ShowTaskDirect(ConfiguredTask):
129
+ def run(self):
130
+ adapter = get_adapter(self.config)
131
+ with adapter.connection_named("show", should_release_connection=False):
132
+ limit = None if self.args.limit < 0 else self.args.limit
133
+ response, table = adapter.execute(self.args.inline_direct, fetch=True, limit=limit)
134
+
135
+ output = io.StringIO()
136
+ if self.args.output == "json":
137
+ table.to_json(path=output)
138
+ else:
139
+ table.print_table(output=output, max_rows=None)
140
+
141
+ fire_event(
142
+ ShowNode(
143
+ node_name="direct-query",
144
+ preview=output.getvalue(),
145
+ is_inline=True,
146
+ output_format=self.args.output,
147
+ unique_id="direct-query",
148
+ quiet=get_flags().QUIET,
149
+ )
150
+ )
dvt/task/snapshot.py ADDED
@@ -0,0 +1,57 @@
1
+ from typing import Optional, Type
2
+
3
+ from dvt.artifacts.schemas.results import NodeStatus
4
+ from dvt.events.types import LogSnapshotResult
5
+ from dvt.graph import ResourceTypeSelector
6
+ from dvt.node_types import NodeType
7
+ from dvt.task import group_lookup
8
+ from dvt.task.base import BaseRunner
9
+ from dvt.task.run import ModelRunner, RunTask
10
+
11
+ from dbt_common.events.base_types import EventLevel
12
+ from dbt_common.events.functions import fire_event
13
+ from dbt_common.exceptions import DbtInternalError
14
+ from dbt_common.utils import cast_dict_to_dict_of_strings
15
+
16
+
17
+ class SnapshotRunner(ModelRunner):
18
+ def describe_node(self) -> str:
19
+ return "snapshot {}".format(self.get_node_representation())
20
+
21
+ def print_result_line(self, result):
22
+ model = result.node
23
+ group = group_lookup.get(model.unique_id)
24
+ cfg = model.config.to_dict(omit_none=True)
25
+ level = EventLevel.ERROR if result.status == NodeStatus.Error else EventLevel.INFO
26
+ fire_event(
27
+ LogSnapshotResult(
28
+ status=result.status,
29
+ description=self.get_node_representation(),
30
+ cfg=cast_dict_to_dict_of_strings(cfg),
31
+ index=self.node_index,
32
+ total=self.num_nodes,
33
+ execution_time=result.execution_time,
34
+ node_info=model.node_info,
35
+ result_message=result.message,
36
+ group=group,
37
+ ),
38
+ level=level,
39
+ )
40
+
41
+
42
+ class SnapshotTask(RunTask):
43
+ def raise_on_first_error(self) -> bool:
44
+ return False
45
+
46
+ def get_node_selector(self):
47
+ if self.manifest is None or self.graph is None:
48
+ raise DbtInternalError("manifest and graph must be set to get perform node selection")
49
+ return ResourceTypeSelector(
50
+ graph=self.graph,
51
+ manifest=self.manifest,
52
+ previous_state=self.previous_state,
53
+ resource_types=[NodeType.Snapshot],
54
+ )
55
+
56
+ def get_runner_type(self, _) -> Optional[Type[BaseRunner]]:
57
+ return SnapshotRunner
dvt/task/sql.py ADDED
@@ -0,0 +1,111 @@
1
+ import traceback
2
+ from abc import abstractmethod
3
+ from datetime import datetime, timezone
4
+ from typing import Generic, TypeVar
5
+
6
+ import dvt.exceptions
7
+ from dvt.contracts.graph.manifest import Manifest
8
+ from dvt.contracts.sql import (
9
+ RemoteCompileResult,
10
+ RemoteCompileResultMixin,
11
+ RemoteRunResult,
12
+ ResultTable,
13
+ )
14
+ from dvt.events.types import SQLRunnerException
15
+ from dvt.task.compile import CompileRunner
16
+
17
+ import dbt_common.exceptions.base
18
+ from dbt_common.events.functions import fire_event
19
+
20
+ SQLResult = TypeVar("SQLResult", bound=RemoteCompileResultMixin)
21
+
22
+
23
+ class GenericSqlRunner(CompileRunner, Generic[SQLResult]):
24
+ def __init__(self, config, adapter, node, node_index, num_nodes) -> None:
25
+ CompileRunner.__init__(self, config, adapter, node, node_index, num_nodes)
26
+
27
+ def handle_exception(self, e, ctx):
28
+ fire_event(
29
+ SQLRunnerException(
30
+ exc=str(e), exc_info=traceback.format_exc(), node_info=self.node.node_info
31
+ )
32
+ )
33
+ # REVIEW: This code is invalid and will always throw.
34
+ if isinstance(e, dbt.exceptions.Exception):
35
+ if isinstance(e, dbt_common.exceptions.DbtRuntimeError):
36
+ e.add_node(ctx.node)
37
+ return e
38
+
39
+ def before_execute(self) -> None:
40
+ pass
41
+
42
+ def after_execute(self, result) -> None:
43
+ pass
44
+
45
+ def compile(self, manifest: Manifest):
46
+ return self.compiler.compile_node(self.node, manifest, {}, write=False)
47
+
48
+ @abstractmethod
49
+ def execute(self, compiled_node, manifest) -> SQLResult:
50
+ pass
51
+
52
+ @abstractmethod
53
+ def from_run_result(self, result, start_time, timing_info) -> SQLResult:
54
+ pass
55
+
56
+ def error_result(self, node, error, start_time, timing_info):
57
+ raise error
58
+
59
+ def ephemeral_result(self, node, start_time, timing_info):
60
+ raise dbt_common.exceptions.base.NotImplementedError(
61
+ "cannot execute ephemeral nodes remotely!"
62
+ )
63
+
64
+
65
+ class SqlCompileRunner(GenericSqlRunner[RemoteCompileResult]):
66
+ def execute(self, compiled_node, manifest) -> RemoteCompileResult:
67
+ return RemoteCompileResult(
68
+ raw_code=compiled_node.raw_code,
69
+ compiled_code=compiled_node.compiled_code,
70
+ node=compiled_node,
71
+ timing=[], # this will get added later
72
+ generated_at=datetime.now(timezone.utc).replace(tzinfo=None),
73
+ )
74
+
75
+ def from_run_result(self, result, start_time, timing_info) -> RemoteCompileResult:
76
+ return RemoteCompileResult(
77
+ raw_code=result.raw_code,
78
+ compiled_code=result.compiled_code,
79
+ node=result.node,
80
+ timing=timing_info,
81
+ generated_at=datetime.now(timezone.utc).replace(tzinfo=None),
82
+ )
83
+
84
+
85
+ class SqlExecuteRunner(GenericSqlRunner[RemoteRunResult]):
86
+ def execute(self, compiled_node, manifest) -> RemoteRunResult:
87
+ _, execute_result = self.adapter.execute(compiled_node.compiled_code, fetch=True)
88
+
89
+ table = ResultTable(
90
+ column_names=list(execute_result.column_names),
91
+ rows=[list(row) for row in execute_result],
92
+ )
93
+
94
+ return RemoteRunResult(
95
+ raw_code=compiled_node.raw_code,
96
+ compiled_code=compiled_node.compiled_code,
97
+ node=compiled_node,
98
+ table=table,
99
+ timing=[],
100
+ generated_at=datetime.now(timezone.utc).replace(tzinfo=None),
101
+ )
102
+
103
+ def from_run_result(self, result, start_time, timing_info) -> RemoteRunResult:
104
+ return RemoteRunResult(
105
+ raw_code=result.raw_code,
106
+ compiled_code=result.compiled_code,
107
+ node=result.node,
108
+ table=result.table,
109
+ timing=timing_info,
110
+ generated_at=datetime.now(timezone.utc).replace(tzinfo=None),
111
+ )