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/debug.py ADDED
@@ -0,0 +1,513 @@
1
+ # coding=utf-8
2
+ import importlib
3
+ import os
4
+ import platform
5
+ import sys
6
+ from collections import namedtuple
7
+ from enum import Flag
8
+ from pathlib import Path
9
+ from typing import Any, Dict, List, Optional, Tuple
10
+
11
+ import dbt.exceptions
12
+ import dbt_common.clients.system
13
+ import dbt_common.exceptions
14
+ from dbt.adapters.factory import get_adapter, register_adapter
15
+ from dbt.artifacts.schemas.results import RunStatus
16
+ from dbt.cli.flags import Flags
17
+
18
+ from dbt.config import PartialProject, Profile, Project
19
+ from dbt.config.dvt_profile import DVTProfile
20
+ from dbt.config.renderer import DbtProjectYamlRenderer, ProfileRenderer
21
+ from dbt.events.types import DebugCmdOut, DebugCmdResult, OpenCommand
22
+ from dbt.links import ProfileConfigDocs
23
+ from dbt.mp_context import get_mp_context
24
+ from dbt.task.base import BaseTask, get_nearest_project_dir
25
+ from dbt.version import get_installed_version
26
+ from dbt_common.events.format import pluralize
27
+ from dbt_common.events.functions import fire_event
28
+ from dbt_common.ui import green, red
29
+
30
+ ONLY_PROFILE_MESSAGE = """
31
+ A project file (dvt_project.yml or dbt_project.yml) was not found in this directory.
32
+ Using the only profile `{}`.
33
+ """.lstrip()
34
+
35
+ MULTIPLE_PROFILE_MESSAGE = """
36
+ A project file (dvt_project.yml or dbt_project.yml) was not found in this directory.
37
+ dvt found the following profiles:
38
+ {}
39
+
40
+ To debug one of these profiles, run:
41
+ dvt debug --profile [profile-name]
42
+ """.lstrip()
43
+
44
+ COULD_NOT_CONNECT_MESSAGE = """
45
+ dbt was unable to connect to the specified database.
46
+ The database returned the following error:
47
+
48
+ >{err}
49
+
50
+ Check your database credentials and try again. For more information, visit:
51
+ {url}
52
+ """.lstrip()
53
+
54
+ MISSING_PROFILE_MESSAGE = """
55
+ dbt looked for a profiles.yml file in {path}, but did
56
+ not find one. For more information on configuring your profile, consult the
57
+ documentation:
58
+
59
+ {url}
60
+ """.lstrip()
61
+
62
+ FILE_NOT_FOUND = "file not found"
63
+
64
+
65
+ SubtaskStatus = namedtuple(
66
+ "SubtaskStatus", ["log_msg", "run_status", "details", "summary_message"]
67
+ )
68
+
69
+
70
+ class DebugRunStatus(Flag):
71
+ SUCCESS = True
72
+ FAIL = False
73
+
74
+
75
+ class DebugTask(BaseTask):
76
+ def __init__(self, args: Flags) -> None:
77
+ super().__init__(args)
78
+ self.profiles_dir = args.PROFILES_DIR
79
+ self.profile_path = os.path.join(self.profiles_dir, "profiles.yml")
80
+ try:
81
+ self.project_dir = get_nearest_project_dir(self.args.project_dir)
82
+ except dbt_common.exceptions.DbtBaseException:
83
+ # we probably couldn't find a project directory. Set project dir
84
+ # to whatever was given, or default to the current directory.
85
+ if args.project_dir:
86
+ self.project_dir = args.project_dir
87
+ else:
88
+ self.project_dir = Path.cwd()
89
+ # DVT: Support both dvt_project.yml and dbt_project.yml
90
+ dvt_project_path = os.path.join(self.project_dir, "dvt_project.yml")
91
+ dbt_project_path = os.path.join(self.project_dir, "dbt_project.yml")
92
+ if os.path.exists(dvt_project_path):
93
+ self.project_path = dvt_project_path
94
+ else:
95
+ self.project_path = dbt_project_path
96
+ self.cli_vars: Dict[str, Any] = args.vars
97
+
98
+ # set by _load_*
99
+ self.profile: Optional[Profile] = None
100
+ self.raw_profile_data: Optional[Dict[str, Any]] = None
101
+ self.profile_name: Optional[str] = None
102
+
103
+ def run(self) -> bool:
104
+ # WARN: this is a legacy workflow that is not compatible with other runtime flags
105
+ if self.args.config_dir:
106
+ fire_event(
107
+ OpenCommand(
108
+ open_cmd=dbt_common.clients.system.open_dir_cmd(),
109
+ profiles_dir=str(self.profiles_dir),
110
+ )
111
+ )
112
+ return DebugRunStatus.SUCCESS.value
113
+
114
+ version: str = get_installed_version().to_version_string(skip_matcher=True)
115
+ fire_event(DebugCmdOut(msg="dbt version: {}".format(version)))
116
+ fire_event(DebugCmdOut(msg="python version: {}".format(sys.version.split()[0])))
117
+ fire_event(DebugCmdOut(msg="python path: {}".format(sys.executable)))
118
+ fire_event(DebugCmdOut(msg="os info: {}".format(platform.platform())))
119
+
120
+ # Load profile if possible, then load adapter info (which requires the profile)
121
+ load_profile_status: SubtaskStatus = self._load_profile()
122
+ fire_event(DebugCmdOut(msg="Using profiles dir at {}".format(self.profiles_dir)))
123
+ fire_event(DebugCmdOut(msg="Using profiles.yml file at {}".format(self.profile_path)))
124
+ fire_event(DebugCmdOut(msg="Using project file at {}".format(self.project_path)))
125
+ if load_profile_status.run_status == RunStatus.Success:
126
+ if self.profile is None:
127
+ raise dbt_common.exceptions.DbtInternalError(
128
+ "Profile should not be None if loading profile completed"
129
+ )
130
+ else:
131
+ adapter_type: str = self.profile.credentials.type
132
+
133
+ adapter_version: str = self._read_adapter_version(
134
+ f"dbt.adapters.{adapter_type}.__version__"
135
+ )
136
+ fire_event(DebugCmdOut(msg="adapter type: {}".format(adapter_type)))
137
+ fire_event(DebugCmdOut(msg="adapter version: {}".format(adapter_version)))
138
+
139
+ # Get project loaded to do additional checks
140
+ load_project_status: SubtaskStatus = self._load_project()
141
+
142
+ dependencies_statuses: List[SubtaskStatus] = []
143
+ if self.args.connection:
144
+ fire_event(DebugCmdOut(msg="Skipping steps before connection verification"))
145
+ else:
146
+ # this job's status not logged since already accounted for in _load_* commands
147
+ self.test_configuration(load_profile_status.log_msg, load_project_status.log_msg)
148
+ dependencies_statuses = self.test_dependencies()
149
+
150
+ # Test connection
151
+ connection_status = self.test_connection()
152
+
153
+ # Log messages from any fails
154
+ all_statuses: List[SubtaskStatus] = [
155
+ load_profile_status,
156
+ load_project_status,
157
+ *dependencies_statuses,
158
+ connection_status,
159
+ ]
160
+ all_failing_statuses: List[SubtaskStatus] = list(
161
+ filter(lambda status: status.run_status == RunStatus.Error, all_statuses)
162
+ )
163
+
164
+ failure_count: int = len(all_failing_statuses)
165
+ if failure_count > 0:
166
+ fire_event(DebugCmdResult(msg=red(f"{(pluralize(failure_count, 'check'))} failed:")))
167
+ for status in all_failing_statuses:
168
+ fire_event(DebugCmdResult(msg=f"{status.summary_message}\n"))
169
+ return DebugRunStatus.FAIL.value
170
+ else:
171
+ fire_event(DebugCmdResult(msg=green("All checks passed!")))
172
+ return DebugRunStatus.SUCCESS.value
173
+
174
+ # ==============================
175
+ # Override for elsewhere in core
176
+ # ==============================
177
+
178
+ def interpret_results(self, results):
179
+ return results
180
+
181
+ # ===============
182
+ # Loading profile
183
+ # ===============
184
+
185
+ def _load_profile(self) -> SubtaskStatus:
186
+ """
187
+ Side effects: load self.profile
188
+ load self.target_name
189
+ load self.raw_profile_data
190
+ """
191
+ if not os.path.exists(self.profile_path):
192
+ return SubtaskStatus(
193
+ log_msg=red("ERROR not found"),
194
+ run_status=RunStatus.Error,
195
+ details=FILE_NOT_FOUND,
196
+ summary_message=MISSING_PROFILE_MESSAGE.format(
197
+ path=self.profile_path, url=ProfileConfigDocs
198
+ ),
199
+ )
200
+
201
+ # DVT: Use read_profile() to get automatic connections → outputs conversion
202
+ from dbt.config.profile import read_profile
203
+ raw_profile_data = read_profile(os.path.dirname(self.profile_path))
204
+ if isinstance(raw_profile_data, dict):
205
+ self.raw_profile_data = raw_profile_data
206
+
207
+ profile_errors = []
208
+ profile_names, summary_message = self._choose_profile_names()
209
+ renderer = ProfileRenderer(self.cli_vars)
210
+ for profile_name in profile_names:
211
+ try:
212
+ # DVT: Use DVTProfile.render instead of Profile.render
213
+ profile: Profile = DVTProfile.render(
214
+ renderer,
215
+ profile_name,
216
+ self.args.profile,
217
+ self.args.target,
218
+ # TODO: Generalize safe access to flags.THREADS:
219
+ # https://github.com/dbt-labs/dbt-core/issues/6259
220
+ getattr(self.args, "threads", None),
221
+ )
222
+ except dbt_common.exceptions.DbtConfigError as exc:
223
+ profile_errors.append(str(exc))
224
+ else:
225
+ if len(profile_names) == 1:
226
+ # if a profile was specified, set it on the task
227
+ self.target_name = self._choose_target_name(profile_name)
228
+ self.profile = profile
229
+
230
+ if profile_errors:
231
+ details = "\n\n".join(profile_errors)
232
+ return SubtaskStatus(
233
+ log_msg=red("ERROR invalid"),
234
+ run_status=RunStatus.Error,
235
+ details=details,
236
+ summary_message=(
237
+ summary_message + f"Profile loading failed for the following reason:"
238
+ f"\n{details}"
239
+ f"\n"
240
+ ),
241
+ )
242
+ else:
243
+ return SubtaskStatus(
244
+ log_msg=green("OK found and valid"),
245
+ run_status=RunStatus.Success,
246
+ details="",
247
+ summary_message="Profile is valid",
248
+ )
249
+
250
+ def _choose_profile_names(self) -> Tuple[List[str], str]:
251
+ project_profile: Optional[str] = None
252
+ if os.path.exists(self.project_path):
253
+ try:
254
+ partial = PartialProject.from_project_root(
255
+ os.path.dirname(self.project_path),
256
+ verify_version=bool(self.args.VERSION_CHECK),
257
+ )
258
+ renderer = DbtProjectYamlRenderer(None, self.cli_vars)
259
+ project_profile = partial.render_profile_name(renderer)
260
+ except dbt.exceptions.DbtProjectError:
261
+ pass
262
+
263
+ args_profile: Optional[str] = getattr(self.args, "profile", None)
264
+
265
+ try:
266
+ return [Profile.pick_profile_name(args_profile, project_profile)], ""
267
+ except dbt_common.exceptions.DbtConfigError:
268
+ pass
269
+ # try to guess
270
+
271
+ profiles = []
272
+ if self.raw_profile_data:
273
+ profiles = [k for k in self.raw_profile_data if k != "config"]
274
+ if project_profile is None:
275
+ summary_message = "Could not load project file\n"
276
+ elif len(profiles) == 0:
277
+ summary_message = "The profiles.yml has no profiles\n"
278
+ elif len(profiles) == 1:
279
+ summary_message = ONLY_PROFILE_MESSAGE.format(profiles[0])
280
+ else:
281
+ summary_message = MULTIPLE_PROFILE_MESSAGE.format(
282
+ "\n".join(" - {}".format(o) for o in profiles)
283
+ )
284
+ return profiles, summary_message
285
+
286
+ def _read_adapter_version(self, module) -> str:
287
+ """read the version out of a standard adapter file"""
288
+ try:
289
+ version = importlib.import_module(module).version
290
+ except ModuleNotFoundError:
291
+ version = red("ERROR not found")
292
+ except Exception as exc:
293
+ version = red("ERROR {}".format(exc))
294
+ raise dbt.exceptions.DbtInternalError(
295
+ f"Error when reading adapter version from {module}: {exc}"
296
+ )
297
+
298
+ return version
299
+
300
+ def _choose_target_name(self, profile_name: str):
301
+ has_raw_profile = (
302
+ self.raw_profile_data is not None and profile_name in self.raw_profile_data
303
+ )
304
+
305
+ if not has_raw_profile:
306
+ return None
307
+
308
+ # mypy appeasement, we checked just above
309
+ assert self.raw_profile_data is not None
310
+ raw_profile = self.raw_profile_data[profile_name]
311
+
312
+ renderer = ProfileRenderer(self.cli_vars)
313
+
314
+ # DVT: Use DVTProfile.render_profile instead of Profile.render_profile
315
+ target_name, _ = DVTProfile.render_profile(
316
+ raw_profile=raw_profile,
317
+ profile_name=profile_name,
318
+ target_override=getattr(self.args, "target", None),
319
+ renderer=renderer,
320
+ )
321
+ return target_name
322
+
323
+ # ===============
324
+ # Loading project
325
+ # ===============
326
+
327
+ def _load_project(self) -> SubtaskStatus:
328
+ """
329
+ Side effect: load self.project
330
+ """
331
+ if not os.path.exists(self.project_path):
332
+ return SubtaskStatus(
333
+ log_msg=red("ERROR not found"),
334
+ run_status=RunStatus.Error,
335
+ details=FILE_NOT_FOUND,
336
+ summary_message=(
337
+ f"Project loading failed for the following reason:"
338
+ f"\n project path <{self.project_path}> not found"
339
+ ),
340
+ )
341
+
342
+ renderer = DbtProjectYamlRenderer(self.profile, self.cli_vars)
343
+
344
+ try:
345
+ self.project = Project.from_project_root(
346
+ str(self.project_dir),
347
+ renderer,
348
+ verify_version=self.args.VERSION_CHECK,
349
+ )
350
+ except dbt_common.exceptions.DbtConfigError as exc:
351
+ return SubtaskStatus(
352
+ log_msg=red("ERROR invalid"),
353
+ run_status=RunStatus.Error,
354
+ details=str(exc),
355
+ summary_message=(
356
+ f"Project loading failed for the following reason:" f"\n{str(exc)}" f"\n"
357
+ ),
358
+ )
359
+ else:
360
+ return SubtaskStatus(
361
+ log_msg=green("OK found and valid"),
362
+ run_status=RunStatus.Success,
363
+ details="",
364
+ summary_message="Project is valid",
365
+ )
366
+
367
+ def _profile_found(self) -> str:
368
+ if not self.raw_profile_data:
369
+ return red("ERROR not found")
370
+ assert self.raw_profile_data is not None
371
+ if self.profile_name in self.raw_profile_data:
372
+ return green("OK found")
373
+ else:
374
+ return red("ERROR not found")
375
+
376
+ def _target_found(self) -> str:
377
+ requirements = self.raw_profile_data and self.profile_name and self.target_name
378
+ if not requirements:
379
+ return red("ERROR not found")
380
+ # mypy appeasement, we checked just above
381
+ assert self.raw_profile_data is not None
382
+ assert self.profile_name is not None
383
+ assert self.target_name is not None
384
+ if self.profile_name not in self.raw_profile_data:
385
+ return red("ERROR not found")
386
+ profiles = self.raw_profile_data[self.profile_name]["outputs"]
387
+ if self.target_name not in profiles:
388
+ return red("ERROR not found")
389
+ else:
390
+ return green("OK found")
391
+
392
+ # ============
393
+ # Config tests
394
+ # ============
395
+
396
+ def test_git(self) -> SubtaskStatus:
397
+ try:
398
+ dbt_common.clients.system.run_cmd(os.getcwd(), ["git", "--help"])
399
+ except dbt_common.exceptions.ExecutableError as exc:
400
+ return SubtaskStatus(
401
+ log_msg=red("ERROR"),
402
+ run_status=RunStatus.Error,
403
+ details="git error",
404
+ summary_message="Error from git --help: {!s}".format(exc),
405
+ )
406
+ else:
407
+ return SubtaskStatus(
408
+ log_msg=green("OK found"),
409
+ run_status=RunStatus.Success,
410
+ details="",
411
+ summary_message="git is installed and on the path",
412
+ )
413
+
414
+ def test_dependencies(self) -> List[SubtaskStatus]:
415
+ fire_event(DebugCmdOut(msg="Required dependencies:"))
416
+
417
+ git_test_status = self.test_git()
418
+ fire_event(DebugCmdResult(msg=f" - git [{git_test_status.log_msg}]\n"))
419
+
420
+ return [git_test_status]
421
+
422
+ def test_configuration(self, profile_status_msg, project_status_msg):
423
+ fire_event(DebugCmdOut(msg="Configuration:"))
424
+ fire_event(DebugCmdOut(msg=f" profiles.yml file [{profile_status_msg}]"))
425
+ # DVT: Use generic project file message
426
+ project_file_name = os.path.basename(self.project_path)
427
+ fire_event(DebugCmdOut(msg=f" {project_file_name} file [{project_status_msg}]"))
428
+
429
+ # skip profile stuff if we can't find a profile name
430
+ if self.profile_name is not None:
431
+ fire_event(
432
+ DebugCmdOut(
433
+ msg=" profile: {} [{}]\n".format(self.profile_name, self._profile_found())
434
+ )
435
+ )
436
+ fire_event(
437
+ DebugCmdOut(
438
+ msg=" target: {} [{}]\n".format(self.target_name, self._target_found())
439
+ )
440
+ )
441
+
442
+ # ===============
443
+ # Connection test
444
+ # ===============
445
+
446
+ @staticmethod
447
+ def attempt_connection(profile) -> Optional[str]:
448
+ """Return a string containing the error message, or None if there was no error."""
449
+ register_adapter(profile, get_mp_context())
450
+ adapter = get_adapter(profile)
451
+ try:
452
+ with adapter.connection_named("debug"):
453
+ # is defined in adapter class
454
+ adapter.debug_query()
455
+ except Exception as exc:
456
+ return COULD_NOT_CONNECT_MESSAGE.format(
457
+ err=str(exc),
458
+ url=ProfileConfigDocs,
459
+ )
460
+ return None
461
+
462
+ def test_connection(self) -> SubtaskStatus:
463
+ if self.profile is None:
464
+ fire_event(DebugCmdOut(msg="Connection test skipped since no profile was found"))
465
+ return SubtaskStatus(
466
+ log_msg=red("SKIPPED"),
467
+ run_status=RunStatus.Skipped,
468
+ details="No profile found",
469
+ summary_message="Connection test skipped since no profile was found",
470
+ )
471
+
472
+ fire_event(DebugCmdOut(msg="Connection:"))
473
+ for k, v in self.profile.credentials.connection_info():
474
+ fire_event(DebugCmdOut(msg=f" {k}: {v}"))
475
+
476
+ connection_result = self.attempt_connection(self.profile)
477
+ if connection_result is None:
478
+ status = SubtaskStatus(
479
+ log_msg=green("OK connection ok"),
480
+ run_status=RunStatus.Success,
481
+ details="",
482
+ summary_message="Connection test passed",
483
+ )
484
+ else:
485
+ status = SubtaskStatus(
486
+ log_msg=red("ERROR"),
487
+ run_status=RunStatus.Error,
488
+ details="Failure in connecting to db",
489
+ summary_message=connection_result,
490
+ )
491
+ fire_event(DebugCmdOut(msg=f" Connection test: [{status.log_msg}]\n"))
492
+ return status
493
+
494
+ @classmethod
495
+ def validate_connection(cls, target_dict) -> None:
496
+ """Validate a connection dictionary. On error, raises a DbtConfigError."""
497
+ target_name = "test"
498
+ # make a fake profile that we can parse
499
+ profile_data = {
500
+ "outputs": {
501
+ target_name: target_dict,
502
+ },
503
+ }
504
+ # this will raise a DbtConfigError on failure
505
+ profile = Profile.from_raw_profile_info(
506
+ raw_profile=profile_data,
507
+ profile_name="",
508
+ target_override=target_name,
509
+ renderer=ProfileRenderer({}),
510
+ )
511
+ result = cls.attempt_connection(profile)
512
+ if result is not None:
513
+ raise dbt.exceptions.DbtProfileError(result, result_type="connection_failure")