dvt-core 0.52.2__cp310-cp310-macosx_10_9_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of dvt-core might be problematic. Click here for more details.

Files changed (275) 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 +2039 -0
  57. dbt/cli/option_types.py +121 -0
  58. dbt/cli/options.py +80 -0
  59. dbt/cli/params.py +804 -0
  60. dbt/cli/requires.py +490 -0
  61. dbt/cli/resolvers.py +50 -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 +624 -0
  74. dbt/compute/federated_executor.py +837 -0
  75. dbt/compute/filter_pushdown.cpython-310-darwin.so +0 -0
  76. dbt/compute/filter_pushdown.py +273 -0
  77. dbt/compute/jar_provisioning.cpython-310-darwin.so +0 -0
  78. dbt/compute/jar_provisioning.py +255 -0
  79. dbt/compute/java_compat.cpython-310-darwin.so +0 -0
  80. dbt/compute/java_compat.py +689 -0
  81. dbt/compute/jdbc_utils.cpython-310-darwin.so +0 -0
  82. dbt/compute/jdbc_utils.py +678 -0
  83. dbt/compute/smart_selector.cpython-310-darwin.so +0 -0
  84. dbt/compute/smart_selector.py +311 -0
  85. dbt/compute/strategies/__init__.py +54 -0
  86. dbt/compute/strategies/base.py +165 -0
  87. dbt/compute/strategies/dataproc.py +207 -0
  88. dbt/compute/strategies/emr.py +203 -0
  89. dbt/compute/strategies/local.py +364 -0
  90. dbt/compute/strategies/standalone.py +262 -0
  91. dbt/config/__init__.py +4 -0
  92. dbt/config/catalogs.py +94 -0
  93. dbt/config/compute.cpython-310-darwin.so +0 -0
  94. dbt/config/compute.py +547 -0
  95. dbt/config/dvt_profile.cpython-310-darwin.so +0 -0
  96. dbt/config/dvt_profile.py +342 -0
  97. dbt/config/profile.py +422 -0
  98. dbt/config/project.py +873 -0
  99. dbt/config/project_utils.py +28 -0
  100. dbt/config/renderer.py +231 -0
  101. dbt/config/runtime.py +553 -0
  102. dbt/config/selectors.py +208 -0
  103. dbt/config/utils.py +77 -0
  104. dbt/constants.py +28 -0
  105. dbt/context/__init__.py +0 -0
  106. dbt/context/base.py +745 -0
  107. dbt/context/configured.py +135 -0
  108. dbt/context/context_config.py +382 -0
  109. dbt/context/docs.py +82 -0
  110. dbt/context/exceptions_jinja.py +178 -0
  111. dbt/context/macro_resolver.py +195 -0
  112. dbt/context/macros.py +171 -0
  113. dbt/context/manifest.py +72 -0
  114. dbt/context/providers.py +2249 -0
  115. dbt/context/query_header.py +13 -0
  116. dbt/context/secret.py +58 -0
  117. dbt/context/target.py +74 -0
  118. dbt/contracts/__init__.py +0 -0
  119. dbt/contracts/files.py +413 -0
  120. dbt/contracts/graph/__init__.py +0 -0
  121. dbt/contracts/graph/manifest.py +1904 -0
  122. dbt/contracts/graph/metrics.py +97 -0
  123. dbt/contracts/graph/model_config.py +70 -0
  124. dbt/contracts/graph/node_args.py +42 -0
  125. dbt/contracts/graph/nodes.py +1806 -0
  126. dbt/contracts/graph/semantic_manifest.py +232 -0
  127. dbt/contracts/graph/unparsed.py +811 -0
  128. dbt/contracts/project.py +417 -0
  129. dbt/contracts/results.py +53 -0
  130. dbt/contracts/selection.py +23 -0
  131. dbt/contracts/sql.py +85 -0
  132. dbt/contracts/state.py +68 -0
  133. dbt/contracts/util.py +46 -0
  134. dbt/deprecations.py +346 -0
  135. dbt/deps/__init__.py +0 -0
  136. dbt/deps/base.py +152 -0
  137. dbt/deps/git.py +195 -0
  138. dbt/deps/local.py +79 -0
  139. dbt/deps/registry.py +130 -0
  140. dbt/deps/resolver.py +149 -0
  141. dbt/deps/tarball.py +120 -0
  142. dbt/docs/source/_ext/dbt_click.py +119 -0
  143. dbt/docs/source/conf.py +32 -0
  144. dbt/env_vars.py +64 -0
  145. dbt/event_time/event_time.py +40 -0
  146. dbt/event_time/sample_window.py +60 -0
  147. dbt/events/__init__.py +15 -0
  148. dbt/events/base_types.py +36 -0
  149. dbt/events/core_types_pb2.py +2 -0
  150. dbt/events/logging.py +108 -0
  151. dbt/events/types.py +2516 -0
  152. dbt/exceptions.py +1486 -0
  153. dbt/flags.py +89 -0
  154. dbt/graph/__init__.py +11 -0
  155. dbt/graph/cli.py +247 -0
  156. dbt/graph/graph.py +172 -0
  157. dbt/graph/queue.py +214 -0
  158. dbt/graph/selector.py +374 -0
  159. dbt/graph/selector_methods.py +975 -0
  160. dbt/graph/selector_spec.py +222 -0
  161. dbt/graph/thread_pool.py +18 -0
  162. dbt/hooks.py +21 -0
  163. dbt/include/README.md +49 -0
  164. dbt/include/__init__.py +3 -0
  165. dbt/include/starter_project/.gitignore +4 -0
  166. dbt/include/starter_project/README.md +15 -0
  167. dbt/include/starter_project/__init__.py +3 -0
  168. dbt/include/starter_project/analyses/.gitkeep +0 -0
  169. dbt/include/starter_project/dbt_project.yml +36 -0
  170. dbt/include/starter_project/macros/.gitkeep +0 -0
  171. dbt/include/starter_project/models/example/my_first_dbt_model.sql +27 -0
  172. dbt/include/starter_project/models/example/my_second_dbt_model.sql +6 -0
  173. dbt/include/starter_project/models/example/schema.yml +21 -0
  174. dbt/include/starter_project/seeds/.gitkeep +0 -0
  175. dbt/include/starter_project/snapshots/.gitkeep +0 -0
  176. dbt/include/starter_project/tests/.gitkeep +0 -0
  177. dbt/internal_deprecations.py +26 -0
  178. dbt/jsonschemas/__init__.py +3 -0
  179. dbt/jsonschemas/jsonschemas.py +309 -0
  180. dbt/jsonschemas/project/0.0.110.json +4717 -0
  181. dbt/jsonschemas/project/0.0.85.json +2015 -0
  182. dbt/jsonschemas/resources/0.0.110.json +2636 -0
  183. dbt/jsonschemas/resources/0.0.85.json +2536 -0
  184. dbt/jsonschemas/resources/latest.json +6773 -0
  185. dbt/links.py +4 -0
  186. dbt/materializations/__init__.py +0 -0
  187. dbt/materializations/incremental/__init__.py +0 -0
  188. dbt/materializations/incremental/microbatch.py +236 -0
  189. dbt/mp_context.py +8 -0
  190. dbt/node_types.py +37 -0
  191. dbt/parser/__init__.py +23 -0
  192. dbt/parser/analysis.py +21 -0
  193. dbt/parser/base.py +548 -0
  194. dbt/parser/common.py +266 -0
  195. dbt/parser/docs.py +52 -0
  196. dbt/parser/fixtures.py +51 -0
  197. dbt/parser/functions.py +30 -0
  198. dbt/parser/generic_test.py +100 -0
  199. dbt/parser/generic_test_builders.py +333 -0
  200. dbt/parser/hooks.py +118 -0
  201. dbt/parser/macros.py +137 -0
  202. dbt/parser/manifest.py +2204 -0
  203. dbt/parser/models.py +573 -0
  204. dbt/parser/partial.py +1178 -0
  205. dbt/parser/read_files.py +445 -0
  206. dbt/parser/schema_generic_tests.py +422 -0
  207. dbt/parser/schema_renderer.py +111 -0
  208. dbt/parser/schema_yaml_readers.py +935 -0
  209. dbt/parser/schemas.py +1466 -0
  210. dbt/parser/search.py +149 -0
  211. dbt/parser/seeds.py +28 -0
  212. dbt/parser/singular_test.py +20 -0
  213. dbt/parser/snapshots.py +44 -0
  214. dbt/parser/sources.py +558 -0
  215. dbt/parser/sql.py +62 -0
  216. dbt/parser/unit_tests.py +621 -0
  217. dbt/plugins/__init__.py +20 -0
  218. dbt/plugins/contracts.py +9 -0
  219. dbt/plugins/exceptions.py +2 -0
  220. dbt/plugins/manager.py +163 -0
  221. dbt/plugins/manifest.py +21 -0
  222. dbt/profiler.py +20 -0
  223. dbt/py.typed +1 -0
  224. dbt/query_analyzer.cpython-310-darwin.so +0 -0
  225. dbt/query_analyzer.py +410 -0
  226. dbt/runners/__init__.py +2 -0
  227. dbt/runners/exposure_runner.py +7 -0
  228. dbt/runners/no_op_runner.py +45 -0
  229. dbt/runners/saved_query_runner.py +7 -0
  230. dbt/selected_resources.py +8 -0
  231. dbt/task/__init__.py +0 -0
  232. dbt/task/base.py +503 -0
  233. dbt/task/build.py +197 -0
  234. dbt/task/clean.py +56 -0
  235. dbt/task/clone.py +161 -0
  236. dbt/task/compile.py +150 -0
  237. dbt/task/compute.py +454 -0
  238. dbt/task/debug.py +505 -0
  239. dbt/task/deps.py +280 -0
  240. dbt/task/docs/__init__.py +3 -0
  241. dbt/task/docs/generate.py +660 -0
  242. dbt/task/docs/index.html +250 -0
  243. dbt/task/docs/serve.py +29 -0
  244. dbt/task/freshness.py +322 -0
  245. dbt/task/function.py +121 -0
  246. dbt/task/group_lookup.py +46 -0
  247. dbt/task/init.py +553 -0
  248. dbt/task/java.py +316 -0
  249. dbt/task/list.py +236 -0
  250. dbt/task/printer.py +175 -0
  251. dbt/task/retry.py +175 -0
  252. dbt/task/run.py +1306 -0
  253. dbt/task/run_operation.py +141 -0
  254. dbt/task/runnable.py +758 -0
  255. dbt/task/seed.py +103 -0
  256. dbt/task/show.py +149 -0
  257. dbt/task/snapshot.py +56 -0
  258. dbt/task/spark.py +414 -0
  259. dbt/task/sql.py +110 -0
  260. dbt/task/target_sync.py +759 -0
  261. dbt/task/test.py +464 -0
  262. dbt/tests/fixtures/__init__.py +1 -0
  263. dbt/tests/fixtures/project.py +620 -0
  264. dbt/tests/util.py +651 -0
  265. dbt/tracking.py +529 -0
  266. dbt/utils/__init__.py +3 -0
  267. dbt/utils/artifact_upload.py +151 -0
  268. dbt/utils/utils.py +408 -0
  269. dbt/version.py +268 -0
  270. dvt_cli/__init__.py +72 -0
  271. dvt_core-0.52.2.dist-info/METADATA +286 -0
  272. dvt_core-0.52.2.dist-info/RECORD +275 -0
  273. dvt_core-0.52.2.dist-info/WHEEL +5 -0
  274. dvt_core-0.52.2.dist-info/entry_points.txt +2 -0
  275. dvt_core-0.52.2.dist-info/top_level.txt +2 -0
dbt/cli/requires.py ADDED
@@ -0,0 +1,490 @@
1
+ import importlib.util
2
+ import os
3
+ import time
4
+ import traceback
5
+ from functools import update_wrapper
6
+ from typing import Dict, Optional
7
+
8
+ from click import Context
9
+
10
+ import dbt.tracking
11
+ from dbt.adapters.factory import adapter_management, get_adapter, register_adapter
12
+ from dbt.cli.exceptions import ExceptionExit, ResultExit
13
+ from dbt.cli.flags import Flags
14
+ from dbt.config import RuntimeConfig
15
+ from dbt.config.catalogs import get_active_write_integration, load_catalogs
16
+ from dbt.config.runtime import UnsetProfile, load_profile, load_project
17
+ from dbt.context.providers import generate_runtime_macro_context
18
+ from dbt.context.query_header import generate_query_header_context
19
+ from dbt.deprecations import show_deprecations_summary
20
+ from dbt.env_vars import KNOWN_ENGINE_ENV_VARS, validate_engine_env_vars
21
+ from dbt.events.logging import setup_event_logger
22
+ from dbt.events.types import (
23
+ ArtifactUploadError,
24
+ CommandCompleted,
25
+ MainEncounteredError,
26
+ MainReportArgs,
27
+ MainReportVersion,
28
+ MainStackTrace,
29
+ MainTrackingUserState,
30
+ ResourceReport,
31
+ )
32
+ from dbt.exceptions import DbtProjectError, FailFastError
33
+ from dbt.flags import get_flag_dict, get_flags, set_flags
34
+ from dbt.mp_context import get_mp_context
35
+ from dbt.parser.manifest import parse_manifest
36
+ from dbt.plugins import set_up_plugin_manager
37
+ from dbt.profiler import profiler
38
+ from dbt.tracking import active_user, initialize_from_flags, track_run
39
+ from dbt.utils import try_get_max_rss_kb
40
+ from dbt.utils.artifact_upload import upload_artifacts
41
+ from dbt.version import installed as installed_version
42
+ from dbt_common.clients.system import get_env
43
+ from dbt_common.context import get_invocation_context, set_invocation_context
44
+ from dbt_common.events.base_types import EventLevel
45
+ from dbt_common.events.event_manager_client import get_event_manager
46
+ from dbt_common.events.functions import LOG_VERSION, fire_event
47
+ from dbt_common.events.helpers import get_json_string_utcnow
48
+ from dbt_common.exceptions import DbtBaseException as DbtException
49
+ from dbt_common.invocation import reset_invocation_id
50
+ from dbt_common.record import (
51
+ Recorder,
52
+ RecorderMode,
53
+ get_record_mode_from_env,
54
+ get_record_types_from_dict,
55
+ get_record_types_from_env,
56
+ )
57
+ from dbt_common.utils import cast_dict_to_dict_of_strings
58
+
59
+
60
+ def _cross_propagate_engine_env_vars(env_dict: Dict[str, str]) -> None:
61
+ for env_var in KNOWN_ENGINE_ENV_VARS:
62
+ if env_var.old_name is not None:
63
+ # If the old name is in the env dict, and not the new name, set the new name based on the old name
64
+ if env_var.old_name in env_dict and env_var.name not in env_dict:
65
+ env_dict[env_var.name] = env_dict[env_var.old_name]
66
+ # If the new name is in the env dict, override the old name with it
67
+ elif env_var.name in env_dict:
68
+ env_dict[env_var.old_name] = env_dict[env_var.name]
69
+
70
+
71
+ def preflight(func):
72
+ def wrapper(*args, **kwargs):
73
+ ctx = args[0]
74
+ assert isinstance(ctx, Context)
75
+ ctx.obj = ctx.obj or {}
76
+
77
+ set_invocation_context({})
78
+
79
+ # Record/Replay
80
+ setup_record_replay()
81
+
82
+ # Must be set after record/replay is set up so that the env can be
83
+ # recorded or replayed if needed.
84
+ env_dict = get_env()
85
+ _cross_propagate_engine_env_vars(env_dict)
86
+ get_invocation_context()._env = env_dict
87
+
88
+ # Flags
89
+ flags = Flags(ctx)
90
+ ctx.obj["flags"] = flags
91
+ set_flags(flags)
92
+ get_event_manager().require_warn_or_error_handling = (
93
+ flags.require_all_warnings_handled_by_warn_error
94
+ )
95
+
96
+ # Reset invocation_id for each 'invocation' of a dbt command (can happen multiple times in a single process)
97
+ reset_invocation_id()
98
+
99
+ # Logging
100
+ callbacks = ctx.obj.get("callbacks", [])
101
+ setup_event_logger(flags=flags, callbacks=callbacks)
102
+
103
+ # Tracking
104
+ initialize_from_flags(flags.SEND_ANONYMOUS_USAGE_STATS, flags.PROFILES_DIR)
105
+ ctx.with_resource(track_run(run_command=flags.WHICH))
106
+
107
+ # Now that we have our logger, fire away!
108
+ fire_event(MainReportVersion(version=str(installed_version), log_version=LOG_VERSION))
109
+ flags_dict_str = cast_dict_to_dict_of_strings(get_flag_dict())
110
+ fire_event(MainReportArgs(args=flags_dict_str))
111
+
112
+ # Deprecation warnings
113
+ flags.fire_deprecations(ctx)
114
+
115
+ if active_user is not None: # mypy appeasement, always true
116
+ fire_event(MainTrackingUserState(user_state=active_user.state()))
117
+
118
+ # Profiling
119
+ if flags.RECORD_TIMING_INFO:
120
+ ctx.with_resource(profiler(enable=True, outfile=flags.RECORD_TIMING_INFO))
121
+
122
+ # Adapter management
123
+ ctx.with_resource(adapter_management())
124
+
125
+ # Validate engine env var restricted name space
126
+ validate_engine_env_vars()
127
+
128
+ return func(*args, **kwargs)
129
+
130
+ return update_wrapper(wrapper, func)
131
+
132
+
133
+ def _validate_java_for_compute_models(manifest):
134
+ """
135
+ Validate Java/PySpark compatibility if any models use compute engines.
136
+
137
+ DVT v0.51.3: This validation runs after manifest parsing to ensure Java
138
+ is compatible with PySpark BEFORE execution begins. This prevents
139
+ confusing runtime errors deep in Spark execution.
140
+
141
+ Only validates if models actually use compute='spark' or similar.
142
+ """
143
+ try:
144
+ # Check if any models use compute engines
145
+ has_compute_models = False
146
+
147
+ # Check models for compute config
148
+ if hasattr(manifest, "nodes"):
149
+ for node in manifest.nodes.values():
150
+ # Check node config for 'compute' setting
151
+ if hasattr(node, "config") and hasattr(node.config, "compute"):
152
+ if node.config.compute: # Not None or empty
153
+ has_compute_models = True
154
+ break
155
+
156
+ if not has_compute_models:
157
+ return # No compute models, skip validation
158
+
159
+ # Models use compute engines - validate Java/PySpark
160
+ from dbt.compute.java_compat import validate_java_for_spark
161
+
162
+ is_valid, msg = validate_java_for_spark()
163
+ if not is_valid:
164
+ # Block execution with clear error
165
+ raise DbtProjectError(
166
+ f"\n{'=' * 60}\n"
167
+ f"DVT Java/PySpark Compatibility Error\n"
168
+ f"{'=' * 60}\n\n"
169
+ f"{msg}\n\n"
170
+ f"Your project has models using compute='spark' which requires\n"
171
+ f"a compatible Java installation.\n"
172
+ f"{'=' * 60}\n"
173
+ )
174
+ except ImportError:
175
+ # java_compat module not available - skip validation
176
+ pass
177
+ except DbtProjectError:
178
+ # Re-raise validation errors
179
+ raise
180
+ except Exception:
181
+ # Don't block on validation errors - let execution proceed
182
+ # and fail naturally if there's a real problem
183
+ pass
184
+
185
+
186
+ def setup_record_replay():
187
+ rec_mode = get_record_mode_from_env()
188
+ rec_types = get_record_types_from_env()
189
+
190
+ recorder: Optional[Recorder] = None
191
+ if rec_mode == RecorderMode.REPLAY:
192
+ previous_recording_path = os.environ.get(
193
+ "DBT_ENGINE_RECORDER_FILE_PATH"
194
+ ) or os.environ.get("DBT_RECORDER_FILE_PATH")
195
+ recorder = Recorder(
196
+ RecorderMode.REPLAY, types=rec_types, previous_recording_path=previous_recording_path
197
+ )
198
+ elif rec_mode == RecorderMode.DIFF:
199
+ previous_recording_path = os.environ.get(
200
+ "DBT_ENGINE_RECORDER_FILE_PATH"
201
+ ) or os.environ.get("DBT_RECORDER_FILE_PATH")
202
+ # ensure types match the previous recording
203
+ types = get_record_types_from_dict(previous_recording_path)
204
+ recorder = Recorder(
205
+ RecorderMode.DIFF, types=types, previous_recording_path=previous_recording_path
206
+ )
207
+ elif rec_mode == RecorderMode.RECORD:
208
+ recorder = Recorder(RecorderMode.RECORD, types=rec_types)
209
+
210
+ get_invocation_context().recorder = recorder
211
+
212
+
213
+ def tear_down_record_replay():
214
+ recorder = get_invocation_context().recorder
215
+ if recorder is not None:
216
+ if recorder.mode == RecorderMode.RECORD:
217
+ recorder.write()
218
+ if recorder.mode == RecorderMode.DIFF:
219
+ recorder.write()
220
+ recorder.write_diffs(diff_file_name="recording_diffs.json")
221
+ elif recorder.mode == RecorderMode.REPLAY:
222
+ recorder.write_diffs("replay_diffs.json")
223
+
224
+
225
+ def postflight(func):
226
+ """The decorator that handles all exception handling for the click commands.
227
+ This decorator must be used before any other decorators that may throw an exception."""
228
+
229
+ def wrapper(*args, **kwargs):
230
+ ctx = args[0]
231
+ start_func = time.perf_counter()
232
+ success = False
233
+
234
+ try:
235
+ result, success = func(*args, **kwargs)
236
+ except FailFastError as e:
237
+ fire_event(MainEncounteredError(exc=str(e)))
238
+ raise ResultExit(e.result)
239
+ except DbtException as e:
240
+ fire_event(MainEncounteredError(exc=str(e)))
241
+ raise ExceptionExit(e)
242
+ except BaseException as e:
243
+ fire_event(MainEncounteredError(exc=str(e)))
244
+ fire_event(MainStackTrace(stack_trace=traceback.format_exc()))
245
+ raise ExceptionExit(e)
246
+ finally:
247
+ # Fire ResourceReport, but only on systems which support the resource
248
+ # module. (Skip it on Windows).
249
+ try:
250
+ if get_flags().upload_to_artifacts_ingest_api:
251
+ upload_artifacts(
252
+ get_flags().project_dir, get_flags().target_path, ctx.command.name
253
+ )
254
+
255
+ except Exception as e:
256
+ fire_event(ArtifactUploadError(msg=str(e)))
257
+
258
+ show_deprecations_summary()
259
+
260
+ if importlib.util.find_spec("resource") is not None:
261
+ import resource
262
+
263
+ rusage = resource.getrusage(resource.RUSAGE_SELF)
264
+ fire_event(
265
+ ResourceReport(
266
+ command_name=ctx.command.name,
267
+ command_success=success,
268
+ command_wall_clock_time=time.perf_counter() - start_func,
269
+ process_user_time=rusage.ru_utime,
270
+ process_kernel_time=rusage.ru_stime,
271
+ process_mem_max_rss=try_get_max_rss_kb() or rusage.ru_maxrss,
272
+ process_in_blocks=rusage.ru_inblock,
273
+ process_out_blocks=rusage.ru_oublock,
274
+ ),
275
+ (
276
+ EventLevel.INFO
277
+ if "flags" in ctx.obj and ctx.obj["flags"].SHOW_RESOURCE_REPORT
278
+ else None
279
+ ),
280
+ )
281
+
282
+ fire_event(
283
+ CommandCompleted(
284
+ command=ctx.command_path,
285
+ success=success,
286
+ completed_at=get_json_string_utcnow(),
287
+ elapsed=time.perf_counter() - start_func,
288
+ )
289
+ )
290
+
291
+ tear_down_record_replay()
292
+
293
+ if not success:
294
+ raise ResultExit(result)
295
+
296
+ return (result, success)
297
+
298
+ return update_wrapper(wrapper, func)
299
+
300
+
301
+ # TODO: UnsetProfile is necessary for deps and clean to load a project.
302
+ # This decorator and its usage can be removed once https://github.com/dbt-labs/dbt-core/issues/6257 is closed.
303
+ def unset_profile(func):
304
+ def wrapper(*args, **kwargs):
305
+ ctx = args[0]
306
+ assert isinstance(ctx, Context)
307
+
308
+ profile = UnsetProfile()
309
+ ctx.obj["profile"] = profile
310
+
311
+ return func(*args, **kwargs)
312
+
313
+ return update_wrapper(wrapper, func)
314
+
315
+
316
+ def profile(func):
317
+ def wrapper(*args, **kwargs):
318
+ ctx = args[0]
319
+ assert isinstance(ctx, Context)
320
+
321
+ flags = ctx.obj["flags"]
322
+ # TODO: Generalize safe access to flags.THREADS:
323
+ # https://github.com/dbt-labs/dbt-core/issues/6259
324
+ threads = getattr(flags, "THREADS", None)
325
+ profile = load_profile(flags.PROJECT_DIR, flags.VARS, flags.PROFILE, flags.TARGET, threads)
326
+ ctx.obj["profile"] = profile
327
+ get_invocation_context().uses_adapter(profile.credentials.type)
328
+
329
+ return func(*args, **kwargs)
330
+
331
+ return update_wrapper(wrapper, func)
332
+
333
+
334
+ def project(func):
335
+ def wrapper(*args, **kwargs):
336
+ ctx = args[0]
337
+ assert isinstance(ctx, Context)
338
+
339
+ # TODO: Decouple target from profile, and remove the need for profile here:
340
+ # https://github.com/dbt-labs/dbt-core/issues/6257
341
+ if not ctx.obj.get("profile"):
342
+ raise DbtProjectError("profile required for project")
343
+
344
+ flags = ctx.obj["flags"]
345
+ # TODO deprecations warnings fired from loading the project will lack
346
+ # the project_id in the snowplow event.
347
+ project = load_project(
348
+ flags.PROJECT_DIR, flags.VERSION_CHECK, ctx.obj["profile"], flags.VARS, validate=True
349
+ )
350
+ ctx.obj["project"] = project
351
+
352
+ # Plugins
353
+ set_up_plugin_manager(project_name=project.project_name)
354
+
355
+ if dbt.tracking.active_user is not None:
356
+ project_id = None if project is None else project.hashed_name()
357
+
358
+ dbt.tracking.track_project_id({"project_id": project_id})
359
+
360
+ return func(*args, **kwargs)
361
+
362
+ return update_wrapper(wrapper, func)
363
+
364
+
365
+ def runtime_config(func):
366
+ """A decorator used by click command functions for generating a runtime
367
+ config given a profile and project.
368
+ """
369
+
370
+ def wrapper(*args, **kwargs):
371
+ ctx = args[0]
372
+ assert isinstance(ctx, Context)
373
+
374
+ req_strs = ["profile", "project"]
375
+ reqs = [ctx.obj.get(req_str) for req_str in req_strs]
376
+
377
+ if None in reqs:
378
+ raise DbtProjectError("profile and project required for runtime_config")
379
+
380
+ config = RuntimeConfig.from_parts(
381
+ ctx.obj["project"],
382
+ ctx.obj["profile"],
383
+ ctx.obj["flags"],
384
+ )
385
+
386
+ ctx.obj["runtime_config"] = config
387
+
388
+ if dbt.tracking.active_user is not None:
389
+ adapter_type = (
390
+ getattr(config.credentials, "type", None)
391
+ if hasattr(config, "credentials")
392
+ else None
393
+ )
394
+ adapter_unique_id = (
395
+ config.credentials.hashed_unique_field()
396
+ if hasattr(config, "credentials")
397
+ else None
398
+ )
399
+
400
+ dbt.tracking.track_adapter_info(
401
+ {
402
+ "adapter_type": adapter_type,
403
+ "adapter_unique_id": adapter_unique_id,
404
+ }
405
+ )
406
+
407
+ return func(*args, **kwargs)
408
+
409
+ return update_wrapper(wrapper, func)
410
+
411
+
412
+ def catalogs(func):
413
+ """A decorator used by click command functions for loading catalogs"""
414
+
415
+ def wrapper(*args, **kwargs):
416
+ ctx = args[0]
417
+ assert isinstance(ctx, Context)
418
+
419
+ req_strs = ["flags", "profile", "project"]
420
+ reqs = [ctx.obj.get(req_str) for req_str in req_strs]
421
+ if None in reqs:
422
+ raise DbtProjectError("profile and flags required to load catalogs")
423
+
424
+ flags = ctx.obj["flags"]
425
+ ctx_project = ctx.obj["project"]
426
+
427
+ _catalogs = load_catalogs(flags.PROJECT_DIR, ctx_project.project_name, flags.VARS)
428
+ ctx.obj["catalogs"] = _catalogs
429
+
430
+ return func(*args, **kwargs)
431
+
432
+ return update_wrapper(wrapper, func)
433
+
434
+
435
+ def manifest(*args0, write=True, write_perf_info=False):
436
+ """A decorator used by click command functions for generating a manifest
437
+ given a profile, project, and runtime config. This also registers the adapter
438
+ from the runtime config and conditionally writes the manifest to disk.
439
+ """
440
+
441
+ def outer_wrapper(func):
442
+ def wrapper(*args, **kwargs):
443
+ ctx = args[0]
444
+ assert isinstance(ctx, Context)
445
+
446
+ setup_manifest(ctx, write=write, write_perf_info=write_perf_info)
447
+ return func(*args, **kwargs)
448
+
449
+ return update_wrapper(wrapper, func)
450
+
451
+ # if there are no args, the decorator was used without params @decorator
452
+ # otherwise, the decorator was called with params @decorator(arg)
453
+ if len(args0) == 0:
454
+ return outer_wrapper
455
+ return outer_wrapper(args0[0])
456
+
457
+
458
+ def setup_manifest(ctx: Context, write: bool = True, write_perf_info: bool = False):
459
+ """Load the manifest and add it to the context."""
460
+ req_strs = ["profile", "project", "runtime_config"]
461
+ reqs = [ctx.obj.get(dep) for dep in req_strs]
462
+
463
+ if None in reqs:
464
+ raise DbtProjectError("profile, project, and runtime_config required for manifest")
465
+
466
+ runtime_config = ctx.obj["runtime_config"]
467
+
468
+ catalogs = ctx.obj["catalogs"] if "catalogs" in ctx.obj else []
469
+ active_integrations = [get_active_write_integration(catalog) for catalog in catalogs]
470
+
471
+ # if a manifest has already been set on the context, don't overwrite it
472
+ if ctx.obj.get("manifest") is None:
473
+ ctx.obj["manifest"] = parse_manifest(
474
+ runtime_config,
475
+ write_perf_info,
476
+ write,
477
+ ctx.obj["flags"].write_json,
478
+ active_integrations,
479
+ )
480
+ adapter = get_adapter(runtime_config)
481
+ else:
482
+ register_adapter(runtime_config, get_mp_context())
483
+ adapter = get_adapter(runtime_config)
484
+ adapter.set_macro_context_generator(generate_runtime_macro_context) # type: ignore[arg-type]
485
+ adapter.set_macro_resolver(ctx.obj["manifest"])
486
+ query_header_context = generate_query_header_context(adapter.config, ctx.obj["manifest"]) # type: ignore[attr-defined]
487
+ adapter.connections.set_query_header(query_header_context)
488
+
489
+ # DVT v0.51.3: Validate Java/PySpark compatibility if any models use compute engines
490
+ _validate_java_for_compute_models(ctx.obj["manifest"])
dbt/cli/resolvers.py ADDED
@@ -0,0 +1,50 @@
1
+ from pathlib import Path
2
+
3
+ from dbt.config.project import PartialProject
4
+ from dbt.exceptions import DbtProjectError
5
+
6
+
7
+ def default_project_dir() -> Path:
8
+ paths = list(Path.cwd().parents)
9
+ paths.insert(0, Path.cwd())
10
+ return next((x for x in paths if (x / "dbt_project.yml").exists()), Path.cwd())
11
+
12
+
13
+ def default_profiles_dir() -> Path:
14
+ """Return the default profiles directory for DVT.
15
+
16
+ Priority:
17
+ 1. CWD with profiles.yml
18
+ 2. CWD/.dvt/profiles.yml
19
+ 3. ~/.dvt/profiles.yml (DVT standard location)
20
+
21
+ Note: DVT does NOT fall back to ~/.dbt/ - use 'dvt migrate' to move configs.
22
+ """
23
+ cwd = Path.cwd()
24
+ home = Path.home()
25
+
26
+ if (cwd / "profiles.yml").exists():
27
+ return cwd
28
+ elif (cwd / ".dvt" / "profiles.yml").exists():
29
+ return cwd / ".dvt"
30
+ else:
31
+ # DVT always uses ~/.dvt/ - no fallback to ~/.dbt/
32
+ return home / ".dvt"
33
+
34
+
35
+ def default_log_path(project_dir: Path, verify_version: bool = False) -> Path:
36
+ """If available, derive a default log path from dbt_project.yml. Otherwise, default to "logs".
37
+ Known limitations:
38
+ 1. Using PartialProject here, so no jinja rendering of log-path.
39
+ 2. Programmatic invocations of the cli via dbtRunner may pass a Project object directly,
40
+ which is not being taken into consideration here to extract a log-path.
41
+ """
42
+ default_log_path = Path("logs")
43
+ try:
44
+ partial = PartialProject.from_project_root(str(project_dir), verify_version=verify_version)
45
+ partial_log_path = partial.project_dict.get("log-path") or default_log_path
46
+ default_log_path = Path(project_dir) / partial_log_path
47
+ except DbtProjectError:
48
+ pass
49
+
50
+ return default_log_path
dbt/cli/types.py ADDED
@@ -0,0 +1,40 @@
1
+ from enum import Enum
2
+ from typing import List
3
+
4
+ from dbt_common.exceptions import DbtInternalError
5
+
6
+
7
+ class Command(Enum):
8
+ BUILD = "build"
9
+ CLEAN = "clean"
10
+ COMPILE = "compile"
11
+ CLONE = "clone"
12
+ DOCS_GENERATE = "generate"
13
+ DOCS_SERVE = "serve"
14
+ DEBUG = "debug"
15
+ DEPS = "deps"
16
+ INIT = "init"
17
+ LIST = "list"
18
+ PARSE = "parse"
19
+ RUN = "run"
20
+ RUN_OPERATION = "run-operation"
21
+ SEED = "seed"
22
+ SHOW = "show"
23
+ SNAPSHOT = "snapshot"
24
+ SOURCE_FRESHNESS = "freshness"
25
+ TEST = "test"
26
+ RETRY = "retry"
27
+
28
+ @classmethod
29
+ def from_str(cls, s: str) -> "Command":
30
+ try:
31
+ return cls(s)
32
+ except ValueError:
33
+ raise DbtInternalError(f"No value '{s}' exists in Command enum")
34
+
35
+ def to_list(self) -> List[str]:
36
+ return {
37
+ Command.DOCS_GENERATE: ["docs", "generate"],
38
+ Command.DOCS_SERVE: ["docs", "serve"],
39
+ Command.SOURCE_FRESHNESS: ["source", "freshness"],
40
+ }.get(self, [self.value])
File without changes
@@ -0,0 +1,83 @@
1
+ import collections
2
+ import dataclasses
3
+ from typing import Any, Dict, List, Optional, Tuple
4
+
5
+ import yaml
6
+
7
+ from dbt import deprecations
8
+ from dbt.clients.yaml_helper import load_yaml_text
9
+
10
+ # the C version is faster, but it doesn't always exist
11
+ try:
12
+ from yaml import CSafeLoader as SafeLoader
13
+ except ImportError:
14
+ from yaml import SafeLoader # type: ignore # noqa: F401
15
+
16
+
17
+ @dataclasses.dataclass
18
+ class YamlCheckFailure:
19
+ failure_type: str
20
+ message: str
21
+
22
+
23
+ def checked_load(contents) -> Tuple[Optional[Dict[str, Any]], List[YamlCheckFailure]]:
24
+ # A hacky (but sadly justified) method for modifying a bit of PyYAML. We create
25
+ # a new local subclass of SafeLoader, since we need to associate state with
26
+ # the static class, but static classes do not have non-static state. This allows
27
+ # us to be sure we have exclusive access to the class.
28
+ class CheckedLoader(SafeLoader):
29
+ check_failures: List[YamlCheckFailure] = []
30
+
31
+ def construct_mapping(self, node, deep=False):
32
+ if not isinstance(node, yaml.MappingNode):
33
+ raise yaml.constructor.ConstructorError(
34
+ None, None, "expected a mapping node, but found %s" % node.id, node.start_mark
35
+ )
36
+ is_override = (
37
+ len(node.value) > 0
38
+ and len(node.value[0]) > 0
39
+ and getattr(node.value[0][0], "value") == "<<"
40
+ )
41
+ self.flatten_mapping(node)
42
+ mapping = {}
43
+ for key_node, value_node in node.value:
44
+ key = self.construct_object(key_node, deep=deep)
45
+ if not isinstance(key, collections.abc.Hashable):
46
+ raise yaml.constructor.ConstructorError(
47
+ "while constructing a mapping",
48
+ node.start_mark,
49
+ "found unhashable key",
50
+ key_node.start_mark,
51
+ )
52
+ value = self.construct_object(value_node, deep=deep)
53
+
54
+ if not is_override and key in mapping:
55
+ start_mark = str(key_node.start_mark)
56
+ if start_mark.startswith(" in"): # this means it was at the top level
57
+ message = f"Duplicate key '{key}' {start_mark.lstrip()}"
58
+ else:
59
+ message = f"Duplicate key '{key}' at {key_node.start_mark}"
60
+
61
+ self.check_failures.append(YamlCheckFailure("duplicate_key", message))
62
+
63
+ mapping[key] = value
64
+ return mapping
65
+
66
+ CheckedLoader.add_constructor(
67
+ yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG, CheckedLoader.construct_mapping
68
+ )
69
+
70
+ dct = load_yaml_text(contents, loader=CheckedLoader)
71
+ check_failures = CheckedLoader.check_failures
72
+
73
+ return (dct, check_failures)
74
+
75
+
76
+ def issue_deprecation_warnings_for_failures(failures: List[YamlCheckFailure], file: str):
77
+ for failure in failures:
78
+ if failure.failure_type == "duplicate_key":
79
+ deprecations.warn(
80
+ "duplicate-yaml-keys-deprecation",
81
+ duplicate_description=failure.message,
82
+ file=file,
83
+ )