dvt-core 0.59.0a51__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.
Files changed (299) hide show
  1. dbt/__init__.py +7 -0
  2. dbt/_pydantic_shim.py +26 -0
  3. dbt/artifacts/__init__.py +0 -0
  4. dbt/artifacts/exceptions/__init__.py +1 -0
  5. dbt/artifacts/exceptions/schemas.py +31 -0
  6. dbt/artifacts/resources/__init__.py +116 -0
  7. dbt/artifacts/resources/base.py +67 -0
  8. dbt/artifacts/resources/types.py +93 -0
  9. dbt/artifacts/resources/v1/analysis.py +10 -0
  10. dbt/artifacts/resources/v1/catalog.py +23 -0
  11. dbt/artifacts/resources/v1/components.py +274 -0
  12. dbt/artifacts/resources/v1/config.py +277 -0
  13. dbt/artifacts/resources/v1/documentation.py +11 -0
  14. dbt/artifacts/resources/v1/exposure.py +51 -0
  15. dbt/artifacts/resources/v1/function.py +52 -0
  16. dbt/artifacts/resources/v1/generic_test.py +31 -0
  17. dbt/artifacts/resources/v1/group.py +21 -0
  18. dbt/artifacts/resources/v1/hook.py +11 -0
  19. dbt/artifacts/resources/v1/macro.py +29 -0
  20. dbt/artifacts/resources/v1/metric.py +172 -0
  21. dbt/artifacts/resources/v1/model.py +145 -0
  22. dbt/artifacts/resources/v1/owner.py +10 -0
  23. dbt/artifacts/resources/v1/saved_query.py +111 -0
  24. dbt/artifacts/resources/v1/seed.py +41 -0
  25. dbt/artifacts/resources/v1/semantic_layer_components.py +72 -0
  26. dbt/artifacts/resources/v1/semantic_model.py +314 -0
  27. dbt/artifacts/resources/v1/singular_test.py +14 -0
  28. dbt/artifacts/resources/v1/snapshot.py +91 -0
  29. dbt/artifacts/resources/v1/source_definition.py +84 -0
  30. dbt/artifacts/resources/v1/sql_operation.py +10 -0
  31. dbt/artifacts/resources/v1/unit_test_definition.py +77 -0
  32. dbt/artifacts/schemas/__init__.py +0 -0
  33. dbt/artifacts/schemas/base.py +191 -0
  34. dbt/artifacts/schemas/batch_results.py +24 -0
  35. dbt/artifacts/schemas/catalog/__init__.py +11 -0
  36. dbt/artifacts/schemas/catalog/v1/__init__.py +0 -0
  37. dbt/artifacts/schemas/catalog/v1/catalog.py +59 -0
  38. dbt/artifacts/schemas/freshness/__init__.py +1 -0
  39. dbt/artifacts/schemas/freshness/v3/__init__.py +0 -0
  40. dbt/artifacts/schemas/freshness/v3/freshness.py +158 -0
  41. dbt/artifacts/schemas/manifest/__init__.py +2 -0
  42. dbt/artifacts/schemas/manifest/v12/__init__.py +0 -0
  43. dbt/artifacts/schemas/manifest/v12/manifest.py +211 -0
  44. dbt/artifacts/schemas/results.py +147 -0
  45. dbt/artifacts/schemas/run/__init__.py +2 -0
  46. dbt/artifacts/schemas/run/v5/__init__.py +0 -0
  47. dbt/artifacts/schemas/run/v5/run.py +184 -0
  48. dbt/artifacts/schemas/upgrades/__init__.py +4 -0
  49. dbt/artifacts/schemas/upgrades/upgrade_manifest.py +174 -0
  50. dbt/artifacts/schemas/upgrades/upgrade_manifest_dbt_version.py +2 -0
  51. dbt/artifacts/utils/validation.py +153 -0
  52. dbt/cli/__init__.py +1 -0
  53. dbt/cli/context.py +17 -0
  54. dbt/cli/exceptions.py +57 -0
  55. dbt/cli/flags.py +560 -0
  56. dbt/cli/main.py +2660 -0
  57. dbt/cli/option_types.py +121 -0
  58. dbt/cli/options.py +80 -0
  59. dbt/cli/params.py +844 -0
  60. dbt/cli/requires.py +490 -0
  61. dbt/cli/resolvers.py +60 -0
  62. dbt/cli/types.py +40 -0
  63. dbt/clients/__init__.py +0 -0
  64. dbt/clients/checked_load.py +83 -0
  65. dbt/clients/git.py +164 -0
  66. dbt/clients/jinja.py +206 -0
  67. dbt/clients/jinja_static.py +245 -0
  68. dbt/clients/registry.py +192 -0
  69. dbt/clients/yaml_helper.py +68 -0
  70. dbt/compilation.py +876 -0
  71. dbt/compute/__init__.py +14 -0
  72. dbt/compute/engines/__init__.py +12 -0
  73. dbt/compute/engines/spark_engine.py +642 -0
  74. dbt/compute/federated_executor.py +1080 -0
  75. dbt/compute/filter_pushdown.py +273 -0
  76. dbt/compute/jar_provisioning.py +273 -0
  77. dbt/compute/java_compat.py +689 -0
  78. dbt/compute/jdbc_utils.py +1252 -0
  79. dbt/compute/metadata/__init__.py +63 -0
  80. dbt/compute/metadata/adapters_registry.py +370 -0
  81. dbt/compute/metadata/catalog_store.py +1036 -0
  82. dbt/compute/metadata/registry.py +674 -0
  83. dbt/compute/metadata/store.py +1020 -0
  84. dbt/compute/smart_selector.py +377 -0
  85. dbt/compute/spark_logger.py +272 -0
  86. dbt/compute/strategies/__init__.py +55 -0
  87. dbt/compute/strategies/base.py +165 -0
  88. dbt/compute/strategies/dataproc.py +207 -0
  89. dbt/compute/strategies/emr.py +203 -0
  90. dbt/compute/strategies/local.py +472 -0
  91. dbt/compute/strategies/standalone.py +262 -0
  92. dbt/config/__init__.py +4 -0
  93. dbt/config/catalogs.py +94 -0
  94. dbt/config/compute.py +513 -0
  95. dbt/config/dvt_profile.py +408 -0
  96. dbt/config/profile.py +422 -0
  97. dbt/config/project.py +888 -0
  98. dbt/config/project_utils.py +48 -0
  99. dbt/config/renderer.py +231 -0
  100. dbt/config/runtime.py +564 -0
  101. dbt/config/selectors.py +208 -0
  102. dbt/config/utils.py +77 -0
  103. dbt/constants.py +28 -0
  104. dbt/context/__init__.py +0 -0
  105. dbt/context/base.py +745 -0
  106. dbt/context/configured.py +135 -0
  107. dbt/context/context_config.py +382 -0
  108. dbt/context/docs.py +82 -0
  109. dbt/context/exceptions_jinja.py +178 -0
  110. dbt/context/macro_resolver.py +195 -0
  111. dbt/context/macros.py +171 -0
  112. dbt/context/manifest.py +72 -0
  113. dbt/context/providers.py +2249 -0
  114. dbt/context/query_header.py +13 -0
  115. dbt/context/secret.py +58 -0
  116. dbt/context/target.py +74 -0
  117. dbt/contracts/__init__.py +0 -0
  118. dbt/contracts/files.py +413 -0
  119. dbt/contracts/graph/__init__.py +0 -0
  120. dbt/contracts/graph/manifest.py +1904 -0
  121. dbt/contracts/graph/metrics.py +97 -0
  122. dbt/contracts/graph/model_config.py +70 -0
  123. dbt/contracts/graph/node_args.py +42 -0
  124. dbt/contracts/graph/nodes.py +1806 -0
  125. dbt/contracts/graph/semantic_manifest.py +232 -0
  126. dbt/contracts/graph/unparsed.py +811 -0
  127. dbt/contracts/project.py +419 -0
  128. dbt/contracts/results.py +53 -0
  129. dbt/contracts/selection.py +23 -0
  130. dbt/contracts/sql.py +85 -0
  131. dbt/contracts/state.py +68 -0
  132. dbt/contracts/util.py +46 -0
  133. dbt/deprecations.py +348 -0
  134. dbt/deps/__init__.py +0 -0
  135. dbt/deps/base.py +152 -0
  136. dbt/deps/git.py +195 -0
  137. dbt/deps/local.py +79 -0
  138. dbt/deps/registry.py +130 -0
  139. dbt/deps/resolver.py +149 -0
  140. dbt/deps/tarball.py +120 -0
  141. dbt/docs/source/_ext/dbt_click.py +119 -0
  142. dbt/docs/source/conf.py +32 -0
  143. dbt/env_vars.py +64 -0
  144. dbt/event_time/event_time.py +40 -0
  145. dbt/event_time/sample_window.py +60 -0
  146. dbt/events/__init__.py +15 -0
  147. dbt/events/base_types.py +36 -0
  148. dbt/events/core_types_pb2.py +2 -0
  149. dbt/events/logging.py +108 -0
  150. dbt/events/types.py +2516 -0
  151. dbt/exceptions.py +1486 -0
  152. dbt/flags.py +89 -0
  153. dbt/graph/__init__.py +11 -0
  154. dbt/graph/cli.py +249 -0
  155. dbt/graph/graph.py +172 -0
  156. dbt/graph/queue.py +214 -0
  157. dbt/graph/selector.py +374 -0
  158. dbt/graph/selector_methods.py +975 -0
  159. dbt/graph/selector_spec.py +222 -0
  160. dbt/graph/thread_pool.py +18 -0
  161. dbt/hooks.py +21 -0
  162. dbt/include/README.md +49 -0
  163. dbt/include/__init__.py +3 -0
  164. dbt/include/data/adapters_registry.duckdb +0 -0
  165. dbt/include/data/build_comprehensive_registry.py +1254 -0
  166. dbt/include/data/build_registry.py +242 -0
  167. dbt/include/data/csv/adapter_queries.csv +33 -0
  168. dbt/include/data/csv/syntax_rules.csv +9 -0
  169. dbt/include/data/csv/type_mappings_bigquery.csv +28 -0
  170. dbt/include/data/csv/type_mappings_databricks.csv +30 -0
  171. dbt/include/data/csv/type_mappings_mysql.csv +40 -0
  172. dbt/include/data/csv/type_mappings_oracle.csv +30 -0
  173. dbt/include/data/csv/type_mappings_postgres.csv +56 -0
  174. dbt/include/data/csv/type_mappings_redshift.csv +33 -0
  175. dbt/include/data/csv/type_mappings_snowflake.csv +38 -0
  176. dbt/include/data/csv/type_mappings_sqlserver.csv +35 -0
  177. dbt/include/dvt_starter_project/README.md +15 -0
  178. dbt/include/dvt_starter_project/__init__.py +3 -0
  179. dbt/include/dvt_starter_project/analyses/PLACEHOLDER +0 -0
  180. dbt/include/dvt_starter_project/dvt_project.yml +39 -0
  181. dbt/include/dvt_starter_project/logs/PLACEHOLDER +0 -0
  182. dbt/include/dvt_starter_project/macros/PLACEHOLDER +0 -0
  183. dbt/include/dvt_starter_project/models/example/my_first_dbt_model.sql +27 -0
  184. dbt/include/dvt_starter_project/models/example/my_second_dbt_model.sql +6 -0
  185. dbt/include/dvt_starter_project/models/example/schema.yml +21 -0
  186. dbt/include/dvt_starter_project/seeds/PLACEHOLDER +0 -0
  187. dbt/include/dvt_starter_project/snapshots/PLACEHOLDER +0 -0
  188. dbt/include/dvt_starter_project/tests/PLACEHOLDER +0 -0
  189. dbt/internal_deprecations.py +26 -0
  190. dbt/jsonschemas/__init__.py +3 -0
  191. dbt/jsonschemas/jsonschemas.py +309 -0
  192. dbt/jsonschemas/project/0.0.110.json +4717 -0
  193. dbt/jsonschemas/project/0.0.85.json +2015 -0
  194. dbt/jsonschemas/resources/0.0.110.json +2636 -0
  195. dbt/jsonschemas/resources/0.0.85.json +2536 -0
  196. dbt/jsonschemas/resources/latest.json +6773 -0
  197. dbt/links.py +4 -0
  198. dbt/materializations/__init__.py +0 -0
  199. dbt/materializations/incremental/__init__.py +0 -0
  200. dbt/materializations/incremental/microbatch.py +236 -0
  201. dbt/mp_context.py +8 -0
  202. dbt/node_types.py +37 -0
  203. dbt/parser/__init__.py +23 -0
  204. dbt/parser/analysis.py +21 -0
  205. dbt/parser/base.py +548 -0
  206. dbt/parser/common.py +266 -0
  207. dbt/parser/docs.py +52 -0
  208. dbt/parser/fixtures.py +51 -0
  209. dbt/parser/functions.py +30 -0
  210. dbt/parser/generic_test.py +100 -0
  211. dbt/parser/generic_test_builders.py +333 -0
  212. dbt/parser/hooks.py +122 -0
  213. dbt/parser/macros.py +137 -0
  214. dbt/parser/manifest.py +2208 -0
  215. dbt/parser/models.py +573 -0
  216. dbt/parser/partial.py +1178 -0
  217. dbt/parser/read_files.py +445 -0
  218. dbt/parser/schema_generic_tests.py +422 -0
  219. dbt/parser/schema_renderer.py +111 -0
  220. dbt/parser/schema_yaml_readers.py +935 -0
  221. dbt/parser/schemas.py +1466 -0
  222. dbt/parser/search.py +149 -0
  223. dbt/parser/seeds.py +28 -0
  224. dbt/parser/singular_test.py +20 -0
  225. dbt/parser/snapshots.py +44 -0
  226. dbt/parser/sources.py +558 -0
  227. dbt/parser/sql.py +62 -0
  228. dbt/parser/unit_tests.py +621 -0
  229. dbt/plugins/__init__.py +20 -0
  230. dbt/plugins/contracts.py +9 -0
  231. dbt/plugins/exceptions.py +2 -0
  232. dbt/plugins/manager.py +163 -0
  233. dbt/plugins/manifest.py +21 -0
  234. dbt/profiler.py +20 -0
  235. dbt/py.typed +1 -0
  236. dbt/query_analyzer.py +410 -0
  237. dbt/runners/__init__.py +2 -0
  238. dbt/runners/exposure_runner.py +7 -0
  239. dbt/runners/no_op_runner.py +45 -0
  240. dbt/runners/saved_query_runner.py +7 -0
  241. dbt/selected_resources.py +8 -0
  242. dbt/task/__init__.py +0 -0
  243. dbt/task/base.py +506 -0
  244. dbt/task/build.py +197 -0
  245. dbt/task/clean.py +56 -0
  246. dbt/task/clone.py +161 -0
  247. dbt/task/compile.py +150 -0
  248. dbt/task/compute.py +458 -0
  249. dbt/task/debug.py +513 -0
  250. dbt/task/deps.py +280 -0
  251. dbt/task/docs/__init__.py +3 -0
  252. dbt/task/docs/api/__init__.py +23 -0
  253. dbt/task/docs/api/catalog.py +204 -0
  254. dbt/task/docs/api/lineage.py +234 -0
  255. dbt/task/docs/api/profile.py +204 -0
  256. dbt/task/docs/api/spark.py +186 -0
  257. dbt/task/docs/generate.py +1002 -0
  258. dbt/task/docs/index.html +250 -0
  259. dbt/task/docs/serve.py +174 -0
  260. dbt/task/dvt_output.py +509 -0
  261. dbt/task/dvt_run.py +282 -0
  262. dbt/task/dvt_seed.py +806 -0
  263. dbt/task/freshness.py +322 -0
  264. dbt/task/function.py +121 -0
  265. dbt/task/group_lookup.py +46 -0
  266. dbt/task/init.py +1022 -0
  267. dbt/task/java.py +316 -0
  268. dbt/task/list.py +236 -0
  269. dbt/task/metadata.py +804 -0
  270. dbt/task/migrate.py +714 -0
  271. dbt/task/printer.py +175 -0
  272. dbt/task/profile.py +1489 -0
  273. dbt/task/profile_serve.py +662 -0
  274. dbt/task/retract.py +441 -0
  275. dbt/task/retry.py +175 -0
  276. dbt/task/run.py +1647 -0
  277. dbt/task/run_operation.py +141 -0
  278. dbt/task/runnable.py +758 -0
  279. dbt/task/seed.py +103 -0
  280. dbt/task/show.py +149 -0
  281. dbt/task/snapshot.py +56 -0
  282. dbt/task/spark.py +414 -0
  283. dbt/task/sql.py +110 -0
  284. dbt/task/target_sync.py +814 -0
  285. dbt/task/test.py +464 -0
  286. dbt/tests/fixtures/__init__.py +1 -0
  287. dbt/tests/fixtures/project.py +620 -0
  288. dbt/tests/util.py +651 -0
  289. dbt/tracking.py +529 -0
  290. dbt/utils/__init__.py +3 -0
  291. dbt/utils/artifact_upload.py +151 -0
  292. dbt/utils/utils.py +408 -0
  293. dbt/version.py +271 -0
  294. dvt_cli/__init__.py +158 -0
  295. dvt_core-0.59.0a51.dist-info/METADATA +288 -0
  296. dvt_core-0.59.0a51.dist-info/RECORD +299 -0
  297. dvt_core-0.59.0a51.dist-info/WHEEL +5 -0
  298. dvt_core-0.59.0a51.dist-info/entry_points.txt +2 -0
  299. dvt_core-0.59.0a51.dist-info/top_level.txt +2 -0
dbt/task/dvt_run.py ADDED
@@ -0,0 +1,282 @@
1
+ # =============================================================================
2
+ # DVT Run Task with Rich UI Enhancement
3
+ # =============================================================================
4
+ # Wrapper around standard RunTask that adds beautiful Rich UI output.
5
+ #
6
+ # DVT v0.58.0: Enhanced CLI output with Rich library
7
+ # DVT v0.59.0a36: Header + Summary panels (works with dbt's event system)
8
+ #
9
+ # IMPORTANT: This wrapper does NOT modify core dbt execution logic.
10
+ # All DVT compute rules are enforced in run.py's ModelRunner.execute().
11
+ #
12
+ # DVT Compute Rules (implemented in run.py):
13
+ # 1. Pushdown Preference: Same-target -> Adapter pushdown (no Spark)
14
+ # 2. Federation Path: Cross-target -> Spark execution
15
+ # 3. Compute Hierarchy: default < model config < CLI --target-compute
16
+ # 4. Target Hierarchy: default < model config < CLI --target
17
+ #
18
+ # NOTE: Rich's Live context conflicts with dbt's fire_event logging system.
19
+ # We use a header+summary approach instead of live-updating progress bars.
20
+ # =============================================================================
21
+
22
+ from __future__ import annotations
23
+
24
+ import os
25
+ import time
26
+ import threading
27
+ from typing import Any, Dict, Optional, AbstractSet
28
+
29
+ from dbt.artifacts.schemas.results import NodeStatus
30
+ from dbt.cli.flags import Flags
31
+ from dbt.config import RuntimeConfig
32
+ from dbt.contracts.graph.manifest import Manifest
33
+ from dbt.task.run import RunTask, ModelRunner
34
+ from dbt.task.dvt_output import DVTMultiBarDisplay, HAS_RICH
35
+
36
+ # Lock for thread-safe Rich console updates
37
+ _console_lock = threading.Lock()
38
+
39
+
40
+ class DVTRunTask(RunTask):
41
+ """
42
+ DVT Run Task with Rich UI enhancement.
43
+
44
+ This class wraps the standard RunTask to add beautiful CLI output
45
+ while preserving all dbt-core and DVT compute logic.
46
+
47
+ DVT v0.59.0a36 Features:
48
+ - Header panel: Shows operation, target, and compute info
49
+ - dbt output: Normal dbt event logging flows during execution
50
+ - Summary panel: Errors grouped by execution path (pushdown vs federation)
51
+ - Warning tracking: Materialization coercions (e.g., view→table)
52
+ - Spark logging: Output captured to target/{compute}_log.txt
53
+
54
+ Note: Does NOT use Rich's Live context (conflicts with dbt's fire_event).
55
+ Instead, prints a header before execution and summary after.
56
+
57
+ Usage:
58
+ task = DVTRunTask(args, config, manifest)
59
+ results = task.run()
60
+ """
61
+
62
+ def __init__(
63
+ self,
64
+ args: Flags,
65
+ config: RuntimeConfig,
66
+ manifest: Manifest,
67
+ batch_map: Optional[Dict[str, Any]] = None,
68
+ ) -> None:
69
+ super().__init__(args, config, manifest, batch_map)
70
+ self._display: Optional[DVTMultiBarDisplay] = None
71
+ self._use_rich_output = HAS_RICH and not getattr(args, 'QUIET', False)
72
+ self._execution_paths: Dict[str, str] = {} # Track pushdown vs federation
73
+ self._spark_logger = None
74
+
75
+ def _get_target_info(self) -> str:
76
+ """Get the current target name for display."""
77
+ cli_target = getattr(self.config.args, 'TARGET', None)
78
+ return cli_target or self.config.target_name or "default"
79
+
80
+ def _get_compute_info(self) -> str:
81
+ """Get the current compute engine for display."""
82
+ cli_compute = getattr(self.config.args, 'TARGET_COMPUTE', None)
83
+ return cli_compute or "auto"
84
+
85
+ def _start_spark_logger(self) -> None:
86
+ """Start Spark output logging to target directory.
87
+
88
+ Note: suppress_console=False so dbt's event output flows normally.
89
+ Spark output is tee'd to the log file for later reference.
90
+ """
91
+ try:
92
+ from dbt.compute.spark_logger import get_spark_logger
93
+
94
+ # Get target directory
95
+ target_dir = os.path.join(os.getcwd(), "target")
96
+ compute_name = self._get_compute_info().replace("-", "_")
97
+ if compute_name == "auto":
98
+ compute_name = "spark"
99
+
100
+ self._spark_logger = get_spark_logger(target_dir, compute_name)
101
+ # Don't suppress console - let dbt events flow normally
102
+ # Spark output is tee'd to file for debugging
103
+ self._spark_logger.start_session(suppress_console=False)
104
+ except Exception:
105
+ # Don't fail if logging setup fails
106
+ self._spark_logger = None
107
+
108
+ def _stop_spark_logger(self) -> None:
109
+ """Stop Spark output logging."""
110
+ if self._spark_logger:
111
+ try:
112
+ self._spark_logger.end_session()
113
+ except Exception:
114
+ pass
115
+ self._spark_logger = None
116
+
117
+ def _determine_execution_path(self, result) -> str:
118
+ """Determine if model was executed via pushdown or federation."""
119
+ # Check if already tracked
120
+ if result.node and result.node.unique_id in self._execution_paths:
121
+ return self._execution_paths[result.node.unique_id]
122
+
123
+ # Check error message for federation hints
124
+ error_msg = result.message or ""
125
+ if "Federated" in error_msg or "JDBC" in error_msg or "Spark" in error_msg:
126
+ return "FEDERATION"
127
+
128
+ # Default to pushdown for all other cases (success or non-federation errors)
129
+ return "PUSHDOWN"
130
+
131
+ def _check_materialization_warning(self, result) -> Optional[str]:
132
+ """Check if model has materialization coercion warning."""
133
+ if not result.node:
134
+ return None
135
+
136
+ # Get model's intended materialization
137
+ config = getattr(result.node, 'config', None)
138
+ if not config:
139
+ return None
140
+
141
+ materialized = getattr(config, 'materialized', 'table')
142
+
143
+ # Check if it's a cross-target view (coerced to table)
144
+ exec_path = self._determine_execution_path(result)
145
+ if exec_path == "FEDERATION" and materialized == "view":
146
+ return "view -> table (cross-target requires table)"
147
+
148
+ return None
149
+
150
+ def before_run(self, adapter, selected_uids: AbstractSet[str]):
151
+ """Called before running models - initialize multi-bar display."""
152
+ # Call parent first (handles schemas, cache, hooks, metadata)
153
+ result = super().before_run(adapter, selected_uids)
154
+
155
+ # Initialize multi-bar Rich display if available (BEFORE Spark logger)
156
+ if self._use_rich_output and hasattr(self, '_flattened_nodes') and self._flattened_nodes:
157
+ try:
158
+ self._display = DVTMultiBarDisplay(
159
+ title="DVT Run",
160
+ operation="run",
161
+ target=self._get_target_info(),
162
+ compute=self._get_compute_info(),
163
+ )
164
+
165
+ # Initialize ALL model tracking upfront from _flattened_nodes
166
+ self._display.initialize_models(self._flattened_nodes)
167
+
168
+ # Print header before dbt output starts
169
+ self._display.start_display()
170
+
171
+ except Exception:
172
+ # Fall back to standard output on any Rich error
173
+ self._display = None
174
+ self._use_rich_output = False
175
+
176
+ # Start Spark output logging AFTER display header is shown
177
+ self._start_spark_logger()
178
+
179
+ return result
180
+
181
+ def _handle_result(self, result) -> None:
182
+ """Handle a single model result - update the specific model's progress bar."""
183
+ # Call parent handler first (fires standard dbt events for logging)
184
+ super()._handle_result(result)
185
+
186
+ # Update the specific model's bar in multi-bar display
187
+ if self._display and result.node:
188
+ try:
189
+ # Determine execution path
190
+ exec_path = self._determine_execution_path(result)
191
+ self._execution_paths[result.node.unique_id] = exec_path
192
+
193
+ # Get error message
194
+ error_msg = result.message if result.status in (
195
+ NodeStatus.Error, NodeStatus.Fail
196
+ ) else None
197
+
198
+ # Check for materialization warning
199
+ warning = self._check_materialization_warning(result)
200
+
201
+ # Map status
202
+ if result.status in (NodeStatus.Error, NodeStatus.Fail):
203
+ status = "error"
204
+ elif result.status == NodeStatus.Skipped:
205
+ status = "skip"
206
+ elif result.status == NodeStatus.Warn:
207
+ status = "warn"
208
+ else:
209
+ status = "pass"
210
+
211
+ # Calculate duration in milliseconds
212
+ duration_ms = (result.execution_time or 0) * 1000
213
+
214
+ # Thread-safe update to the model's progress bar
215
+ with _console_lock:
216
+ self._display.update_model_complete(
217
+ unique_id=result.node.unique_id,
218
+ status=status,
219
+ duration_ms=duration_ms,
220
+ execution_path=exec_path,
221
+ error_message=error_msg,
222
+ warning=warning,
223
+ )
224
+
225
+ except Exception:
226
+ # Silently ignore Rich display errors
227
+ pass
228
+
229
+ def after_run(self, adapter, results) -> None:
230
+ """Called after all models complete - show summary."""
231
+ # Stop Spark logging FIRST so we can print to console
232
+ self._stop_spark_logger()
233
+
234
+ # Stop multi-bar display and show summary
235
+ if self._display:
236
+ try:
237
+ self._display.stop_display()
238
+ self._display.print_summary()
239
+ except Exception:
240
+ pass
241
+
242
+ # Call parent (handles end hooks)
243
+ super().after_run(adapter, results)
244
+
245
+ def task_end_messages(self, results) -> None:
246
+ """Override to prevent duplicate output when using Rich."""
247
+ if self._display:
248
+ # Rich display handles summary, skip default messages
249
+ return
250
+
251
+ # Fall back to standard dbt output
252
+ super().task_end_messages(results)
253
+
254
+
255
+ def create_dvt_run_task(
256
+ args: Flags,
257
+ config: RuntimeConfig,
258
+ manifest: Manifest,
259
+ batch_map: Optional[Dict[str, Any]] = None,
260
+ ) -> RunTask:
261
+ """
262
+ Factory function to create appropriate run task.
263
+
264
+ Returns DVTRunTask with Rich UI if available and not in quiet mode,
265
+ otherwise returns standard RunTask.
266
+
267
+ Args:
268
+ args: CLI flags
269
+ config: Runtime configuration
270
+ manifest: Project manifest
271
+ batch_map: Optional batch map for retry
272
+
273
+ Returns:
274
+ RunTask instance (DVTRunTask or standard RunTask)
275
+ """
276
+ # Check if we should use Rich output
277
+ use_rich = HAS_RICH and not getattr(args, 'QUIET', False)
278
+
279
+ if use_rich:
280
+ return DVTRunTask(args, config, manifest, batch_map)
281
+ else:
282
+ return RunTask(args, config, manifest, batch_map)