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/exceptions.py ADDED
@@ -0,0 +1,1486 @@
1
+ import io
2
+ import json
3
+ import re
4
+ from typing import TYPE_CHECKING, Any, Dict, List, Mapping, Optional, Union
5
+
6
+ from dbt.node_types import REFABLE_NODE_TYPES, AccessType, NodeType
7
+ from dbt_common.constants import SECRET_ENV_PREFIX
8
+ from dbt_common.dataclass_schema import ValidationError
9
+ from dbt_common.exceptions import (
10
+ CommandResultError,
11
+ CompilationError,
12
+ DbtConfigError,
13
+ DbtInternalError,
14
+ DbtRuntimeError,
15
+ DbtValidationError,
16
+ env_secrets,
17
+ scrub_secrets,
18
+ )
19
+
20
+ if TYPE_CHECKING:
21
+ import agate
22
+
23
+
24
+ class ContractBreakingChangeError(DbtRuntimeError):
25
+ CODE = 10016
26
+ MESSAGE = "Breaking Change to Contract"
27
+
28
+ def __init__(
29
+ self,
30
+ breaking_changes: List[str],
31
+ node=None,
32
+ ) -> None:
33
+ self.breaking_changes = breaking_changes
34
+ super().__init__(self.message(), node)
35
+
36
+ @property
37
+ def type(self):
38
+ return "Breaking change to contract"
39
+
40
+ def message(self):
41
+ reasons = "\n - ".join(self.breaking_changes)
42
+
43
+ return (
44
+ "While comparing to previous project state, dbt detected a breaking change to an enforced contract."
45
+ f"\n - {reasons}\n"
46
+ "Consider making an additive (non-breaking) change instead, if possible.\n"
47
+ "Otherwise, create a new model version: https://docs.getdbt.com/docs/collaborate/govern/model-versions"
48
+ )
49
+
50
+
51
+ class ParsingError(DbtRuntimeError):
52
+ CODE = 10015
53
+ MESSAGE = "Parsing Error"
54
+
55
+ @property
56
+ def type(self):
57
+ return "Parsing"
58
+
59
+
60
+ class dbtPluginError(DbtRuntimeError):
61
+ CODE = 10020
62
+ MESSAGE = "Plugin Error"
63
+
64
+
65
+ # TODO: this isn't raised in the core codebase. Is it raised elsewhere?
66
+ class JSONValidationError(DbtValidationError):
67
+ def __init__(self, typename, errors) -> None:
68
+ self.typename = typename
69
+ self.errors = errors
70
+ self.errors_message = ", ".join(errors)
71
+ msg = f'Invalid arguments passed to "{self.typename}" instance: {self.errors_message}'
72
+ super().__init__(msg)
73
+
74
+ def __reduce__(self):
75
+ # see https://stackoverflow.com/a/36342588 for why this is necessary
76
+ return (JSONValidationError, (self.typename, self.errors))
77
+
78
+
79
+ class AliasError(DbtValidationError):
80
+ pass
81
+
82
+
83
+ class DependencyError(Exception):
84
+ CODE = 10006
85
+ MESSAGE = "Dependency Error"
86
+
87
+
88
+ class FailFastError(DbtRuntimeError):
89
+ CODE = 10013
90
+ MESSAGE = "FailFast Error"
91
+
92
+ def __init__(self, msg: str, result=None, node=None) -> None:
93
+ super().__init__(msg=msg, node=node)
94
+ self.result = result
95
+
96
+ @property
97
+ def type(self):
98
+ return "FailFast"
99
+
100
+
101
+ class DbtProjectError(DbtConfigError):
102
+ pass
103
+
104
+
105
+ class DbtSelectorsError(DbtConfigError):
106
+ pass
107
+
108
+
109
+ class DbtProfileError(DbtConfigError):
110
+ pass
111
+
112
+
113
+ class DbtExclusivePropertyUseError(DbtConfigError):
114
+ pass
115
+
116
+
117
+ class InvalidSelectorError(DbtRuntimeError):
118
+ def __init__(self, name: str) -> None:
119
+ self.name = name
120
+ super().__init__(name)
121
+
122
+
123
+ class DuplicateYamlKeyError(CompilationError):
124
+ pass
125
+
126
+
127
+ # compilation level exceptions
128
+ class GraphDependencyNotFoundError(CompilationError):
129
+ def __init__(self, node, dependency: str) -> None:
130
+ self.node = node
131
+ self.dependency = dependency
132
+ super().__init__(msg=self.get_message())
133
+
134
+ def get_message(self) -> str:
135
+ msg = f"'{self.node.unique_id}' depends on '{self.dependency}' which is not in the graph!"
136
+ return msg
137
+
138
+
139
+ class ForeignKeyConstraintToSyntaxError(CompilationError):
140
+ def __init__(self, node, expression: str) -> None:
141
+ self.expression = expression
142
+ self.node = node
143
+ super().__init__(msg=self.get_message())
144
+
145
+ def get_message(self) -> str:
146
+ msg = f"'{self.node.unique_id}' defines a foreign key constraint 'to' expression which is not valid 'ref' or 'source' syntax: {self.expression}."
147
+
148
+ return msg
149
+
150
+
151
+ # client level exceptions
152
+
153
+
154
+ class NoSupportedLanguagesFoundError(CompilationError):
155
+ def __init__(self, node) -> None:
156
+ self.node = node
157
+ self.msg = f"No supported_languages found in materialization macro {self.node.name}"
158
+ super().__init__(msg=self.msg)
159
+
160
+
161
+ class MaterializtionMacroNotUsedError(CompilationError):
162
+ def __init__(self, node) -> None:
163
+ self.node = node
164
+ self.msg = "Only materialization macros can be used with this function"
165
+ super().__init__(msg=self.msg)
166
+
167
+
168
+ class MacroNamespaceNotStringError(CompilationError):
169
+ def __init__(self, kwarg_type: Any) -> None:
170
+ self.kwarg_type = kwarg_type
171
+ super().__init__(msg=self.get_message())
172
+
173
+ def get_message(self) -> str:
174
+ msg = (
175
+ "The macro_namespace parameter to adapter.dispatch "
176
+ f"is a {self.kwarg_type}, not a string"
177
+ )
178
+ return msg
179
+
180
+
181
+ class UnknownGitCloningProblemError(DbtRuntimeError):
182
+ def __init__(self, repo: str) -> None:
183
+ self.repo = scrub_secrets(repo, env_secrets())
184
+ super().__init__(msg=self.get_message())
185
+
186
+ def get_message(self) -> str:
187
+ msg = f"""\
188
+ Something went wrong while cloning {self.repo}
189
+ Check the debug logs for more information
190
+ """
191
+ return msg
192
+
193
+
194
+ class NoAdaptersAvailableError(DbtRuntimeError):
195
+ def __init__(self) -> None:
196
+ super().__init__(msg=self.get_message())
197
+
198
+ def get_message(self) -> str:
199
+ msg = "No adapters available. Learn how to install an adapter by going to https://docs.getdbt.com/docs/connect-adapters#install-using-the-cli"
200
+ return msg
201
+
202
+
203
+ class BadSpecError(DbtInternalError):
204
+ def __init__(self, repo, revision, error) -> None:
205
+ self.repo = repo
206
+ self.revision = revision
207
+ self.stderr = scrub_secrets(error.stderr.strip(), env_secrets())
208
+ super().__init__(msg=self.get_message())
209
+
210
+ def get_message(self) -> str:
211
+ msg = f"Error checking out spec='{self.revision}' for repo {self.repo}\n{self.stderr}"
212
+ return msg
213
+
214
+
215
+ class GitCloningError(DbtInternalError):
216
+ def __init__(self, repo: str, revision: str, error: CommandResultError) -> None:
217
+ self.repo = repo
218
+ self.revision = revision
219
+ self.error = error
220
+ super().__init__(msg=self.get_message())
221
+
222
+ def get_message(self) -> str:
223
+ stderr = self.error.stderr.strip()
224
+ if "usage: git" in stderr:
225
+ stderr = stderr.split("\nusage: git")[0]
226
+ if re.match("fatal: destination path '(.+)' already exists", stderr):
227
+ self.error.cmd = list(scrub_secrets(str(self.error.cmd), env_secrets()))
228
+ raise self.error
229
+
230
+ msg = f"Error checking out spec='{self.revision}' for repo {self.repo}\n{stderr}"
231
+ return scrub_secrets(msg, env_secrets())
232
+
233
+
234
+ class GitCheckoutError(BadSpecError):
235
+ pass
236
+
237
+
238
+ class OperationError(CompilationError):
239
+ def __init__(self, operation_name) -> None:
240
+ self.operation_name = operation_name
241
+ super().__init__(msg=self.get_message())
242
+
243
+ def get_message(self) -> str:
244
+ msg = (
245
+ f"dbt encountered an error when attempting to create a {self.operation_name}. "
246
+ "If this error persists, please create an issue at: \n\n"
247
+ "https://github.com/dbt-labs/dbt-core"
248
+ )
249
+
250
+ return msg
251
+
252
+
253
+ # context level exceptions
254
+ class ZipStrictWrongTypeError(CompilationError):
255
+ def __init__(self, exc) -> None:
256
+ self.exc = exc
257
+ msg = str(self.exc)
258
+ super().__init__(msg=msg)
259
+
260
+
261
+ class SetStrictWrongTypeError(CompilationError):
262
+ def __init__(self, exc) -> None:
263
+ self.exc = exc
264
+ msg = str(self.exc)
265
+ super().__init__(msg=msg)
266
+
267
+
268
+ class LoadAgateTableValueError(CompilationError):
269
+ def __init__(self, exc: ValueError, node) -> None:
270
+ self.exc = exc
271
+ self.node = node
272
+ msg = str(self.exc)
273
+ super().__init__(msg=msg)
274
+
275
+
276
+ class LoadAgateTableNotSeedError(CompilationError):
277
+ def __init__(self, resource_type, node) -> None:
278
+ self.resource_type = resource_type
279
+ self.node = node
280
+ msg = f"can only load_agate_table for seeds (got a {self.resource_type})"
281
+ super().__init__(msg=msg)
282
+
283
+
284
+ class PackageNotInDepsError(CompilationError):
285
+ def __init__(self, package_name: str, node) -> None:
286
+ self.package_name = package_name
287
+ self.node = node
288
+ msg = f"Node package named {self.package_name} not found!"
289
+ super().__init__(msg=msg)
290
+
291
+
292
+ class OperationsCannotRefEphemeralNodesError(CompilationError):
293
+ def __init__(self, target_name: str, node) -> None:
294
+ self.target_name = target_name
295
+ self.node = node
296
+ msg = f"Operations can not ref() ephemeral nodes, but {target_name} is ephemeral"
297
+ super().__init__(msg=msg)
298
+
299
+
300
+ class PersistDocsValueTypeError(CompilationError):
301
+ def __init__(self, persist_docs: Any) -> None:
302
+ self.persist_docs = persist_docs
303
+ msg = (
304
+ "Invalid value provided for 'persist_docs'. Expected dict "
305
+ f"but received {type(self.persist_docs)}"
306
+ )
307
+ super().__init__(msg=msg)
308
+
309
+
310
+ class InlineModelConfigError(CompilationError):
311
+ def __init__(self, node) -> None:
312
+ self.node = node
313
+ msg = "Invalid inline model config"
314
+ super().__init__(msg=msg)
315
+
316
+
317
+ class ConflictingConfigKeysError(CompilationError):
318
+ def __init__(self, oldkey: str, newkey: str, node) -> None:
319
+ self.oldkey = oldkey
320
+ self.newkey = newkey
321
+ self.node = node
322
+ msg = f'Invalid config, has conflicting keys "{self.oldkey}" and "{self.newkey}"'
323
+ super().__init__(msg=msg)
324
+
325
+
326
+ class NumberSourceArgsError(CompilationError):
327
+ def __init__(self, args, node) -> None:
328
+ self.args = args
329
+ self.node = node
330
+ msg = f"source() takes exactly two arguments ({len(self.args)} given)"
331
+ super().__init__(msg=msg)
332
+
333
+
334
+ class RequiredVarNotFoundError(CompilationError):
335
+ def __init__(self, var_name: str, merged: Dict, node) -> None:
336
+ self.var_name = var_name
337
+ self.merged = merged
338
+ self.node = node
339
+ super().__init__(msg=self.get_message())
340
+
341
+ def get_message(self) -> str:
342
+ if self.node is not None:
343
+ node_name = self.node.name
344
+ else:
345
+ node_name = "<Configuration>"
346
+
347
+ dct = {k: self.merged[k] for k in self.merged}
348
+ pretty_vars = json.dumps(dct, sort_keys=True, indent=4)
349
+
350
+ msg = f"Required var '{self.var_name}' not found in config:\nVars supplied to {node_name} = {pretty_vars}"
351
+ return scrub_secrets(msg, self.var_secrets())
352
+
353
+ def var_secrets(self) -> List[str]:
354
+ return [v for k, v in self.merged.items() if k.startswith(SECRET_ENV_PREFIX) and v.strip()]
355
+
356
+
357
+ class PackageNotFoundForMacroError(CompilationError):
358
+ def __init__(self, package_name: str) -> None:
359
+ self.package_name = package_name
360
+ msg = f"Could not find package '{self.package_name}'"
361
+ super().__init__(msg=msg)
362
+
363
+
364
+ class SecretEnvVarLocationError(ParsingError):
365
+ def __init__(self, env_var_name: str) -> None:
366
+ self.env_var_name = env_var_name
367
+ super().__init__(msg=self.get_message())
368
+
369
+ def get_message(self) -> str:
370
+ msg = (
371
+ "Secret env vars are allowed only in profiles.yml or packages.yml. "
372
+ f"Found '{self.env_var_name}' referenced elsewhere."
373
+ )
374
+ return msg
375
+
376
+
377
+ class BooleanError(CompilationError):
378
+ def __init__(self, return_value: Any, macro_name: str) -> None:
379
+ self.return_value = return_value
380
+ self.macro_name = macro_name
381
+ super().__init__(msg=self.get_message())
382
+
383
+ def get_message(self) -> str:
384
+ msg = (
385
+ f"Macro '{self.macro_name}' returns '{self.return_value}'. It is not type 'bool' "
386
+ "and cannot not be converted reliably to a bool."
387
+ )
388
+ return msg
389
+
390
+
391
+ class RefArgsError(CompilationError):
392
+ def __init__(self, node, args) -> None:
393
+ self.node = node
394
+ self.args = args
395
+ super().__init__(msg=self.get_message())
396
+
397
+ def get_message(self) -> str:
398
+ msg = f"ref() takes at most two arguments ({len(self.args)} given)"
399
+ return msg
400
+
401
+
402
+ class MetricArgsError(CompilationError):
403
+ def __init__(self, node, args) -> None:
404
+ self.node = node
405
+ self.args = args
406
+ super().__init__(msg=self.get_message())
407
+
408
+ def get_message(self) -> str:
409
+ msg = f"metric() takes at most two arguments ({len(self.args)} given)"
410
+ return msg
411
+
412
+
413
+ class RefBadContextError(CompilationError):
414
+ def __init__(self, node, args) -> None:
415
+ self.node = node
416
+ self.args = args.positional_args # type: ignore
417
+ self.kwargs = args.keyword_args # type: ignore
418
+ super().__init__(msg=self.get_message())
419
+
420
+ def get_message(self) -> str:
421
+ # This explicitly references model['name'], instead of model['alias'], for
422
+ # better error messages. Ex. If models foo_users and bar_users are aliased
423
+ # to 'users', in their respective schemas, then you would want to see
424
+ # 'bar_users' in your error messge instead of just 'users'.
425
+ if isinstance(self.node, dict):
426
+ model_name = self.node["name"]
427
+ else:
428
+ model_name = self.node.name
429
+
430
+ ref_args = ", ".join("'{}'".format(a) for a in self.args)
431
+
432
+ keyword_args = ""
433
+ if self.kwargs:
434
+ keyword_args = ", ".join(
435
+ "{}='{}'".format(k, v) for k, v in self.kwargs.items() # type: ignore
436
+ )
437
+ keyword_args = "," + keyword_args
438
+
439
+ ref_string = f"{{{{ ref({ref_args}{keyword_args}) }}}}"
440
+
441
+ msg = f"""dbt was unable to infer all dependencies for the model "{model_name}".
442
+ This typically happens when ref() is placed within a conditional block.
443
+
444
+ To fix this, add the following hint to the top of the model "{model_name}":
445
+
446
+ -- depends_on: {ref_string}"""
447
+
448
+ return msg
449
+
450
+
451
+ class DocArgsError(CompilationError):
452
+ def __init__(self, node, args) -> None:
453
+ self.node = node
454
+ self.args = args
455
+ super().__init__(msg=self.get_message())
456
+
457
+ def get_message(self) -> str:
458
+ msg = f"doc() takes at most two arguments ({len(self.args)} given)"
459
+ return msg
460
+
461
+
462
+ class DocTargetNotFoundError(CompilationError):
463
+ def __init__(
464
+ self, node, target_doc_name: str, target_doc_package: Optional[str] = None
465
+ ) -> None:
466
+ self.node = node
467
+ self.target_doc_name = target_doc_name
468
+ self.target_doc_package = target_doc_package
469
+ super().__init__(msg=self.get_message())
470
+
471
+ def get_message(self) -> str:
472
+ target_package_string = ""
473
+ if self.target_doc_package is not None:
474
+ target_package_string = f"in package '{self.target_doc_package}' "
475
+ msg = f"Documentation for '{self.node.unique_id}' depends on doc '{self.target_doc_name}' {target_package_string} which was not found"
476
+ return msg
477
+
478
+
479
+ class MacroDispatchArgError(CompilationError):
480
+ def __init__(self, macro_name: str) -> None:
481
+ self.macro_name = macro_name
482
+ super().__init__(msg=self.get_message())
483
+
484
+ def get_message(self) -> str:
485
+ msg = f"""\
486
+ The "packages" argument of adapter.dispatch() has been deprecated.
487
+ Use the "macro_namespace" argument instead.
488
+
489
+ Raised during dispatch for: {self.macro_name}
490
+
491
+ For more information, see:
492
+
493
+ https://docs.getdbt.com/reference/dbt-jinja-functions/dispatch
494
+ """
495
+ return msg
496
+
497
+
498
+ class DuplicateMacroNameError(CompilationError):
499
+ def __init__(self, node_1, node_2, namespace: str) -> None:
500
+ self.node_1 = node_1
501
+ self.node_2 = node_2
502
+ self.namespace = namespace
503
+ super().__init__(msg=self.get_message())
504
+
505
+ def get_message(self) -> str:
506
+ duped_name = self.node_1.name
507
+ if self.node_1.package_name != self.node_2.package_name:
508
+ extra = f' ("{self.node_1.package_name}" and "{self.node_2.package_name}" are both in the "{self.namespace}" namespace)'
509
+ else:
510
+ extra = ""
511
+
512
+ msg = (
513
+ f'dbt found two macros with the name "{duped_name}" in the namespace "{self.namespace}"{extra}. '
514
+ "Since these macros have the same name and exist in the same "
515
+ "namespace, dbt will be unable to decide which to call. To fix this, "
516
+ f"change the name of one of these macros:\n- {self.node_1.unique_id} "
517
+ f"({self.node_1.original_file_path})\n- {self.node_2.unique_id} ({self.node_2.original_file_path})"
518
+ )
519
+
520
+ return msg
521
+
522
+
523
+ class MacroResultAlreadyLoadedError(CompilationError):
524
+ def __init__(self, result_name) -> None:
525
+ self.result_name = result_name
526
+ super().__init__(msg=self.get_message())
527
+
528
+ def get_message(self) -> str:
529
+ msg = f"The 'statement' result named '{self.result_name}' has already been loaded into a variable"
530
+
531
+ return msg
532
+
533
+
534
+ # parser level exceptions
535
+ class DictParseError(ParsingError):
536
+ def __init__(self, exc: ValidationError, node) -> None:
537
+ self.exc = exc
538
+ self.node = node
539
+ msg = self.validator_error_message(exc)
540
+ super().__init__(msg=msg)
541
+
542
+
543
+ class ConfigUpdateError(ParsingError):
544
+ def __init__(self, exc: ValidationError, node) -> None:
545
+ self.exc = exc
546
+ self.node = node
547
+ msg = self.validator_error_message(exc)
548
+ super().__init__(msg=msg)
549
+
550
+
551
+ class PythonParsingError(ParsingError):
552
+ def __init__(self, exc: SyntaxError, node) -> None:
553
+ self.exc = exc
554
+ self.node = node
555
+ super().__init__(msg=self.get_message())
556
+
557
+ def get_message(self) -> str:
558
+ validated_exc = self.validator_error_message(self.exc)
559
+ msg = f"{validated_exc}\n{self.exc.text}"
560
+ return msg
561
+
562
+
563
+ class PythonLiteralEvalError(ParsingError):
564
+ def __init__(self, exc: Exception, node) -> None:
565
+ self.exc = exc
566
+ self.node = node
567
+ super().__init__(msg=self.get_message())
568
+
569
+ def get_message(self) -> str:
570
+ msg = (
571
+ f"Error when trying to literal_eval an arg to dbt.ref(), dbt.source(), dbt.config() or dbt.config.get() \n{self.exc}\n"
572
+ "https://docs.python.org/3/library/ast.html#ast.literal_eval\n"
573
+ "In dbt python model, `dbt.ref`, `dbt.source`, `dbt.config`, `dbt.config.get` function args only support Python literal structures"
574
+ )
575
+
576
+ return msg
577
+
578
+
579
+ class ModelConfigError(ParsingError):
580
+ def __init__(self, exc: ValidationError, node) -> None:
581
+ self.msg = self.validator_error_message(exc)
582
+ self.node = node
583
+ super().__init__(msg=self.msg)
584
+
585
+
586
+ class YamlParseListError(ParsingError):
587
+ def __init__(
588
+ self,
589
+ path: str,
590
+ key: str,
591
+ yaml_data: List,
592
+ cause,
593
+ ) -> None:
594
+ self.path = path
595
+ self.key = key
596
+ self.yaml_data = yaml_data
597
+ self.cause = cause
598
+ super().__init__(msg=self.get_message())
599
+
600
+ def get_message(self) -> str:
601
+ if isinstance(self.cause, str):
602
+ reason = self.cause
603
+ elif isinstance(self.cause, ValidationError):
604
+ reason = self.validator_error_message(self.cause)
605
+ else:
606
+ reason = self.cause.msg
607
+ msg = f"Invalid {self.key} config given in {self.path} @ {self.key}: {self.yaml_data} - {reason}"
608
+ return msg
609
+
610
+
611
+ class YamlParseDictError(ParsingError):
612
+ def __init__(
613
+ self,
614
+ path: str,
615
+ key: str,
616
+ yaml_data: Dict[str, Any],
617
+ cause,
618
+ ) -> None:
619
+ self.path = path
620
+ self.key = key
621
+ self.yaml_data = yaml_data
622
+ self.cause = cause
623
+ super().__init__(msg=self.get_message())
624
+
625
+ def get_message(self) -> str:
626
+ if isinstance(self.cause, str):
627
+ reason = self.cause
628
+ elif isinstance(self.cause, ValidationError):
629
+ reason = self.validator_error_message(self.cause)
630
+ else:
631
+ reason = self.cause.msg
632
+ msg = f"Invalid {self.key} config given in {self.path} @ {self.key}: {self.yaml_data} - {reason}"
633
+ return msg
634
+
635
+
636
+ class YamlLoadError(ParsingError):
637
+ def __init__(
638
+ self,
639
+ path: str,
640
+ exc: DbtValidationError,
641
+ project_name: Optional[str] = None,
642
+ ) -> None:
643
+ self.project_name = project_name
644
+ self.path = path
645
+ self.exc = exc
646
+ super().__init__(msg=self.get_message())
647
+
648
+ def get_message(self) -> str:
649
+ reason = self.validator_error_message(self.exc)
650
+
651
+ msg = f"Error reading {self.project_name}: {self.path} - {reason}"
652
+
653
+ return msg
654
+
655
+
656
+ class TestConfigError(ParsingError):
657
+ def __init__(self, exc: ValidationError, node) -> None:
658
+ self.msg = self.validator_error_message(exc)
659
+ self.node = node
660
+ super().__init__(msg=self.msg)
661
+
662
+
663
+ class SchemaConfigError(ParsingError):
664
+ def __init__(self, exc: ValidationError, node) -> None:
665
+ self.msg = self.validator_error_message(exc)
666
+ self.node = node
667
+ super().__init__(msg=self.msg)
668
+
669
+
670
+ class SnapshopConfigError(ParsingError):
671
+ def __init__(self, exc: ValidationError, node) -> None:
672
+ self.msg = self.validator_error_message(exc)
673
+ self.node = node
674
+ super().__init__(msg=self.msg)
675
+
676
+
677
+ class DbtReferenceError(ParsingError):
678
+ def __init__(self, unique_id: str, ref_unique_id: str, access: AccessType, scope: str) -> None:
679
+ self.unique_id = unique_id
680
+ self.ref_unique_id = ref_unique_id
681
+ self.access = access
682
+ self.scope = scope
683
+ self.scope_type = "group" if self.access == AccessType.Private else "package"
684
+ super().__init__(msg=self.get_message())
685
+
686
+ def get_message(self) -> str:
687
+ return (
688
+ f"Node {self.unique_id} attempted to reference node {self.ref_unique_id}, "
689
+ f"which is not allowed because the referenced node is {self.access} to the '{self.scope}' {self.scope_type}."
690
+ )
691
+
692
+
693
+ class InvalidAccessTypeError(ParsingError):
694
+ def __init__(
695
+ self, unique_id: str, field_value: str, materialization: Optional[str] = None
696
+ ) -> None:
697
+ self.unique_id = unique_id
698
+ self.field_value = field_value
699
+ self.materialization = materialization
700
+
701
+ with_materialization = (
702
+ f"with '{self.materialization}' materialization " if self.materialization else ""
703
+ )
704
+ msg = f"Node {self.unique_id} {with_materialization}has an invalid value ({self.field_value}) for the access field"
705
+ super().__init__(msg=msg)
706
+
707
+
708
+ class InvalidUnitTestGivenInput(ParsingError):
709
+ def __init__(self, input: str) -> None:
710
+ msg = f"Unit test given inputs must be either a 'ref', 'source' or 'this' call. Got: '{input}'."
711
+ super().__init__(msg=msg)
712
+
713
+
714
+ class SameKeyNestedError(CompilationError):
715
+ def __init__(self) -> None:
716
+ msg = "Test cannot have the same key at the top-level and in config"
717
+ super().__init__(msg=msg)
718
+
719
+
720
+ class TestArgIncludesModelError(CompilationError):
721
+ def __init__(self) -> None:
722
+ msg = 'Test arguments include "model", which is a reserved argument'
723
+ super().__init__(msg=msg)
724
+
725
+
726
+ class UnexpectedTestNamePatternError(CompilationError):
727
+ def __init__(self, test_name: str) -> None:
728
+ self.test_name = test_name
729
+ msg = f"Test name string did not match expected pattern: {self.test_name}"
730
+ super().__init__(msg=msg)
731
+
732
+
733
+ class CustomMacroPopulatingConfigValueError(CompilationError):
734
+ def __init__(
735
+ self,
736
+ target_name: str,
737
+ name: str,
738
+ key: str,
739
+ err_msg: str,
740
+ column_name: Optional[str] = None,
741
+ ) -> None:
742
+ self.target_name = target_name
743
+ self.column_name = column_name
744
+ self.name = name
745
+ self.key = key
746
+ self.err_msg = err_msg
747
+ super().__init__(msg=self.get_message())
748
+
749
+ def get_message(self) -> str:
750
+ # Generic tests do not include custom macros in the Jinja
751
+ # rendering context, so this will almost always fail. As it
752
+ # currently stands, the error message is inscrutable, which
753
+ # has caused issues for some projects migrating from
754
+ # pre-0.20.0 to post-0.20.0.
755
+ # See https://github.com/dbt-labs/dbt-core/issues/4103
756
+ # and https://github.com/dbt-labs/dbt-core/issues/5294
757
+
758
+ msg = (
759
+ f"The {self.target_name}.{self.column_name} column's "
760
+ f'"{self.name}" test references an undefined '
761
+ f"macro in its {self.key} configuration argument. "
762
+ f"The macro {self.err_msg}.\n"
763
+ "Please note that the generic test configuration parser "
764
+ "currently does not support using custom macros to "
765
+ "populate configuration values"
766
+ )
767
+ return msg
768
+
769
+
770
+ class TagsNotListOfStringsError(CompilationError):
771
+ def __init__(self, tags: Any) -> None:
772
+ self.tags = tags
773
+ msg = f"got {self.tags} ({type(self.tags)}) for tags, expected a list of strings"
774
+ super().__init__(msg=msg)
775
+
776
+
777
+ class TagNotStringError(CompilationError):
778
+ def __init__(self, tag: Any) -> None:
779
+ self.tag = tag
780
+ msg = f"got {self.tag} ({type(self.tag)}) for tag, expected a str"
781
+ super().__init__(msg=msg)
782
+
783
+
784
+ class TestNameNotStringError(ParsingError):
785
+ def __init__(self, test_name: Any) -> None:
786
+ self.test_name = test_name
787
+ super().__init__(msg=self.get_message())
788
+
789
+ def get_message(self) -> str:
790
+ msg = f"test name must be a str, got {type(self.test_name)} (value {self.test_name})"
791
+ return msg
792
+
793
+
794
+ class TestArgsNotDictError(ParsingError):
795
+ def __init__(self, test_args: Any) -> None:
796
+ self.test_args = test_args
797
+ super().__init__(msg=self.get_message())
798
+
799
+ def get_message(self) -> str:
800
+ msg = f"test arguments must be a dict, got {type(self.test_args)} (value {self.test_args})"
801
+ return msg
802
+
803
+
804
+ class TestDefinitionDictLengthError(ParsingError):
805
+ def __init__(self, test):
806
+ self.test = test
807
+ super().__init__(msg=self.get_message())
808
+
809
+ def get_message(self) -> str:
810
+ msg = (
811
+ "test definition dictionary must have exactly one key, got"
812
+ f" {self.test} instead ({len(self.test)} keys)"
813
+ )
814
+ return msg
815
+
816
+
817
+ class TestTypeError(ParsingError):
818
+ def __init__(self, test: Any):
819
+ self.test = test
820
+ super().__init__(msg=self.get_message())
821
+
822
+ def get_message(self) -> str:
823
+ msg = f"test must be dict or str, got {type(self.test)} (value {self.test})"
824
+ return msg
825
+
826
+
827
+ # This is triggered across multiple files
828
+ class EnvVarMissingError(ParsingError):
829
+ def __init__(self, var: str):
830
+ self.var = var
831
+ super().__init__(msg=self.get_message())
832
+
833
+ def get_message(self) -> str:
834
+ msg = f"Env var required but not provided: '{self.var}'"
835
+ return msg
836
+
837
+
838
+ class TargetNotFoundError(CompilationError):
839
+ def __init__(
840
+ self,
841
+ node,
842
+ target_name: str,
843
+ target_kind: str,
844
+ target_package: Optional[str] = None,
845
+ target_version: Optional[Union[str, float]] = None,
846
+ disabled: Optional[bool] = None,
847
+ ):
848
+ self.node = node
849
+ self.target_name = target_name
850
+ self.target_kind = target_kind
851
+ self.target_package = target_package
852
+ self.target_version = target_version
853
+ self.disabled = disabled
854
+ super().__init__(msg=self.get_message())
855
+
856
+ def get_message(self) -> str:
857
+ original_file_path = self.node.original_file_path
858
+ unique_id = self.node.unique_id
859
+ resource_type_title = self.node.resource_type.title()
860
+
861
+ if self.disabled is None:
862
+ reason = "was not found or is disabled"
863
+ elif self.disabled is True:
864
+ reason = "is disabled"
865
+ else:
866
+ reason = "was not found"
867
+
868
+ target_version_string = ""
869
+ if self.target_version is not None:
870
+ target_version_string = f"with version '{self.target_version}' "
871
+
872
+ target_package_string = ""
873
+ if self.target_package is not None:
874
+ target_package_string = f"in package or project '{self.target_package}' "
875
+
876
+ msg = (
877
+ f"{resource_type_title} '{unique_id}' ({original_file_path}) depends on a "
878
+ f"{self.target_kind} named '{self.target_name}' {target_version_string}{target_package_string}which {reason}"
879
+ )
880
+ return msg
881
+
882
+
883
+ class DuplicateSourcePatchNameError(CompilationError):
884
+ def __init__(self, patch_1, patch_2):
885
+ self.patch_1 = patch_1
886
+ self.patch_2 = patch_2
887
+ super().__init__(msg=self.get_message())
888
+
889
+ def get_message(self) -> str:
890
+ name = f"{self.patch_1.overrides}.{self.patch_1.name}"
891
+ fix = self._fix_dupe_msg(
892
+ self.patch_1.path,
893
+ self.patch_2.path,
894
+ name,
895
+ "sources",
896
+ )
897
+ msg = (
898
+ f"dbt found two schema.yml entries for the same source named "
899
+ f"{self.patch_1.name} in package {self.patch_1.overrides}. Sources may only be "
900
+ f"overridden a single time. To fix this, {fix}"
901
+ )
902
+ return msg
903
+
904
+
905
+ class DuplicateMacroPatchNameError(CompilationError):
906
+ def __init__(self, patch_1, existing_patch_path):
907
+ self.patch_1 = patch_1
908
+ self.existing_patch_path = existing_patch_path
909
+ super().__init__(msg=self.get_message())
910
+
911
+ def get_message(self) -> str:
912
+ package_name = self.patch_1.package_name
913
+ name = self.patch_1.name
914
+ fix = self._fix_dupe_msg(
915
+ self.patch_1.original_file_path, self.existing_patch_path, name, "macros"
916
+ )
917
+ msg = (
918
+ f"dbt found two schema.yml entries for the same macro in package "
919
+ f"{package_name} named {name}. Macros may only be described a single "
920
+ f"time. To fix this, {fix}"
921
+ )
922
+ return msg
923
+
924
+
925
+ # core level exceptions
926
+ class DuplicateAliasError(AliasError):
927
+ def __init__(self, kwargs: Mapping[str, Any], aliases: Mapping[str, str], canonical_key: str):
928
+ self.kwargs = kwargs
929
+ self.aliases = aliases
930
+ self.canonical_key = canonical_key
931
+ super().__init__(msg=self.get_message())
932
+
933
+ def get_message(self) -> str:
934
+ # dupe found: go through the dict so we can have a nice-ish error
935
+ key_names = ", ".join(
936
+ "{}".format(k) for k in self.kwargs if self.aliases.get(k) == self.canonical_key
937
+ )
938
+ msg = f'Got duplicate keys: ({key_names}) all map to "{self.canonical_key}"'
939
+ return msg
940
+
941
+
942
+ # deps exceptions
943
+ class MultipleVersionGitDepsError(DependencyError):
944
+ def __init__(self, git: str, requested):
945
+ self.git = git
946
+ self.requested = requested
947
+ msg = (
948
+ "git dependencies should contain exactly one version. "
949
+ f"{self.git} contains: {self.requested}"
950
+ )
951
+ super().__init__(msg)
952
+
953
+
954
+ class DuplicateProjectDependencyError(DependencyError):
955
+ def __init__(self, project_name: str):
956
+ self.project_name = project_name
957
+ msg = (
958
+ f'Found duplicate project "{self.project_name}". This occurs when '
959
+ "a dependency has the same project name as some other dependency."
960
+ )
961
+ super().__init__(msg)
962
+
963
+
964
+ class DuplicateDependencyToRootError(DependencyError):
965
+ def __init__(self, project_name: str):
966
+ self.project_name = project_name
967
+ msg = (
968
+ "Found a dependency with the same name as the root project "
969
+ f'"{self.project_name}". Package names must be unique in a project.'
970
+ " Please rename one of these packages."
971
+ )
972
+ super().__init__(msg)
973
+
974
+
975
+ class MismatchedDependencyTypeError(DependencyError):
976
+ def __init__(self, new, old):
977
+ self.new = new
978
+ self.old = old
979
+ msg = (
980
+ f"Cannot incorporate {self.new} ({self.new.__class__.__name__}) in {self.old} "
981
+ f"({self.old.__class__.__name__}): mismatched types"
982
+ )
983
+ super().__init__(msg)
984
+
985
+
986
+ class PackageVersionNotFoundError(DependencyError):
987
+ def __init__(
988
+ self,
989
+ package_name: str,
990
+ version_range,
991
+ available_versions: List[str],
992
+ should_version_check: bool,
993
+ ):
994
+ self.package_name = package_name
995
+ self.version_range = version_range
996
+ self.available_versions = available_versions
997
+ self.should_version_check = should_version_check
998
+ super().__init__(self.get_message())
999
+
1000
+ def get_message(self) -> str:
1001
+ base_msg = (
1002
+ "Could not find a matching compatible version for package {}\n"
1003
+ " Requested range: {}\n"
1004
+ " Compatible versions: {}\n"
1005
+ )
1006
+ addendum = (
1007
+ (
1008
+ "\n"
1009
+ " Not shown: package versions incompatible with installed version of dbt-core\n"
1010
+ " To include them, run 'dbt --no-version-check deps'"
1011
+ )
1012
+ if self.should_version_check
1013
+ else ""
1014
+ )
1015
+ msg = (
1016
+ base_msg.format(self.package_name, self.version_range, self.available_versions)
1017
+ + addendum
1018
+ )
1019
+ return msg
1020
+
1021
+
1022
+ class PackageNotFoundError(DependencyError):
1023
+ def __init__(self, package_name: str):
1024
+ self.package_name = package_name
1025
+ msg = f"Package {self.package_name} was not found in the package index"
1026
+ super().__init__(msg)
1027
+
1028
+
1029
+ # config level exceptions
1030
+ class ProfileConfigError(DbtProfileError):
1031
+ def __init__(self, exc: ValidationError):
1032
+ self.exc = exc
1033
+ msg = self.validator_error_message(self.exc)
1034
+ super().__init__(msg=msg)
1035
+
1036
+
1037
+ class ProjectContractError(DbtProjectError):
1038
+ def __init__(self, exc: ValidationError):
1039
+ self.exc = exc
1040
+ msg = self.validator_error_message(self.exc)
1041
+ super().__init__(msg=msg)
1042
+
1043
+
1044
+ class ProjectContractBrokenError(DbtProjectError):
1045
+ def __init__(self, exc: ValidationError):
1046
+ self.exc = exc
1047
+ msg = self.validator_error_message(self.exc)
1048
+ super().__init__(msg=msg)
1049
+
1050
+
1051
+ class ConfigContractBrokenError(DbtProjectError):
1052
+ def __init__(self, exc: ValidationError):
1053
+ self.exc = exc
1054
+ msg = self.validator_error_message(self.exc)
1055
+ super().__init__(msg=msg)
1056
+
1057
+
1058
+ class NonUniquePackageNameError(CompilationError):
1059
+ def __init__(self, project_name: str):
1060
+ self.project_name = project_name
1061
+ super().__init__(msg=self.get_message())
1062
+
1063
+ def get_message(self) -> str:
1064
+ msg = (
1065
+ "dbt found more than one package with the name "
1066
+ f'"{self.project_name}" included in this project. Package '
1067
+ "names must be unique in a project. Please rename "
1068
+ "one of these packages."
1069
+ )
1070
+ return msg
1071
+
1072
+
1073
+ class UninstalledPackagesFoundError(CompilationError):
1074
+ def __init__(
1075
+ self,
1076
+ count_packages_specified: int,
1077
+ count_packages_installed: int,
1078
+ packages_specified_path: str,
1079
+ packages_install_path: str,
1080
+ ):
1081
+ self.count_packages_specified = count_packages_specified
1082
+ self.count_packages_installed = count_packages_installed
1083
+ self.packages_specified_path = packages_specified_path
1084
+ self.packages_install_path = packages_install_path
1085
+ super().__init__(msg=self.get_message())
1086
+
1087
+ def get_message(self) -> str:
1088
+ msg = (
1089
+ f"dbt found {self.count_packages_specified} package(s) "
1090
+ f"specified in {self.packages_specified_path}, but only "
1091
+ f"{self.count_packages_installed} package(s) installed "
1092
+ f'in {self.packages_install_path}. Run "dbt deps" to '
1093
+ "install package dependencies."
1094
+ )
1095
+ return msg
1096
+
1097
+
1098
+ class OptionNotYamlDictError(CompilationError):
1099
+ def __init__(self, var_type, option_name):
1100
+ self.var_type = var_type
1101
+ self.option_name = option_name
1102
+ super().__init__(msg=self.get_message())
1103
+
1104
+ def get_message(self) -> str:
1105
+ type_name = self.var_type.__name__
1106
+
1107
+ msg = f"The --{self.option_name} argument must be a YAML dictionary, but was of type '{type_name}'"
1108
+ return msg
1109
+
1110
+
1111
+ # contracts level
1112
+ class UnrecognizedCredentialTypeError(CompilationError):
1113
+ def __init__(self, typename: str, supported_types: List):
1114
+ self.typename = typename
1115
+ self.supported_types = supported_types
1116
+ super().__init__(msg=self.get_message())
1117
+
1118
+ def get_message(self) -> str:
1119
+ msg = 'Unrecognized credentials type "{}" - supported types are ({})'.format(
1120
+ self.typename, ", ".join('"{}"'.format(t) for t in self.supported_types)
1121
+ )
1122
+ return msg
1123
+
1124
+
1125
+ # jinja exceptions
1126
+
1127
+
1128
+ class PatchTargetNotFoundError(CompilationError):
1129
+ def __init__(self, patches: Dict):
1130
+ self.patches = patches
1131
+ super().__init__(msg=self.get_message())
1132
+
1133
+ def get_message(self) -> str:
1134
+ patch_list = "\n\t".join(
1135
+ f"model {p.name} (referenced in path {p.original_file_path})"
1136
+ for p in self.patches.values()
1137
+ )
1138
+ msg = f"dbt could not find models for the following patches:\n\t{patch_list}"
1139
+ return msg
1140
+
1141
+
1142
+ class MissingRelationError(CompilationError):
1143
+ def __init__(self, relation, model=None):
1144
+ self.relation = relation
1145
+ self.model = model
1146
+ msg = f"Relation {self.relation} not found!"
1147
+ super().__init__(msg=msg)
1148
+
1149
+
1150
+ class AmbiguousAliasError(CompilationError):
1151
+ def __init__(self, node_1, node_2, duped_name=None):
1152
+ self.node_1 = node_1
1153
+ self.node_2 = node_2
1154
+ if duped_name is None:
1155
+ self.duped_name = f"{self.node_1.database}.{self.node_1.schema}.{self.node_1.alias}"
1156
+ else:
1157
+ self.duped_name = duped_name
1158
+ super().__init__(msg=self.get_message())
1159
+
1160
+ def get_message(self) -> str:
1161
+
1162
+ msg = (
1163
+ f'dbt found two resources with the database representation "{self.duped_name}".\ndbt '
1164
+ "cannot create two resources with identical database representations. "
1165
+ "To fix this,\nchange the configuration of one of these resources:"
1166
+ f"\n- {self.node_1.unique_id} ({self.node_1.original_file_path})\n- {self.node_2.unique_id} ({self.node_2.original_file_path})"
1167
+ )
1168
+ return msg
1169
+
1170
+
1171
+ class AmbiguousResourceNameRefError(CompilationError):
1172
+ def __init__(self, duped_name, unique_ids, node=None):
1173
+ self.duped_name = duped_name
1174
+ self.unique_ids = unique_ids
1175
+ self.packages = [unique_id.split(".")[1] for unique_id in unique_ids]
1176
+ super().__init__(msg=self.get_message(), node=node)
1177
+
1178
+ def get_message(self) -> str:
1179
+ formatted_unique_ids = "'{0}'".format("', '".join(self.unique_ids))
1180
+ formatted_packages = "'{0}'".format("' or '".join(self.packages))
1181
+ msg = (
1182
+ f"When referencing '{self.duped_name}', dbt found nodes in multiple packages: {formatted_unique_ids}"
1183
+ f"\nTo fix this, use two-argument 'ref', with the package name first: {formatted_packages}"
1184
+ )
1185
+ return msg
1186
+
1187
+
1188
+ class AmbiguousCatalogMatchError(CompilationError):
1189
+ def __init__(self, unique_id: str, match_1, match_2):
1190
+ self.unique_id = unique_id
1191
+ self.match_1 = match_1
1192
+ self.match_2 = match_2
1193
+ super().__init__(msg=self.get_message())
1194
+
1195
+ def get_match_string(self, match):
1196
+ match_schema = match.get("metadata", {}).get("schema")
1197
+ match_name = match.get("metadata", {}).get("name")
1198
+ return f"{match_schema}.{match_name}"
1199
+
1200
+ def get_message(self) -> str:
1201
+ msg = (
1202
+ "dbt found two relations in your warehouse with similar database identifiers. "
1203
+ "dbt\nis unable to determine which of these relations was created by the model "
1204
+ f'"{self.unique_id}".\nIn order for dbt to correctly generate the catalog, one '
1205
+ "of the following relations must be deleted or renamed:\n\n - "
1206
+ f"{self.get_match_string(self.match_1)}\n - {self.get_match_string(self.match_2)}"
1207
+ )
1208
+
1209
+ return msg
1210
+
1211
+
1212
+ class DependencyNotFoundError(CompilationError):
1213
+ def __init__(self, node, node_description, required_pkg):
1214
+ self.node = node
1215
+ self.node_description = node_description
1216
+ self.required_pkg = required_pkg
1217
+ super().__init__(msg=self.get_message())
1218
+
1219
+ def get_message(self) -> str:
1220
+ msg = (
1221
+ f"Error while parsing {self.node_description}.\nThe required package "
1222
+ f'"{self.required_pkg}" was not found. Is the package installed?\n'
1223
+ "Hint: You may need to run `dbt deps`."
1224
+ )
1225
+
1226
+ return msg
1227
+
1228
+
1229
+ class DuplicatePatchPathError(CompilationError):
1230
+ def __init__(self, patch_1, existing_patch_path):
1231
+ self.patch_1 = patch_1
1232
+ self.existing_patch_path = existing_patch_path
1233
+ super().__init__(msg=self.get_message())
1234
+
1235
+ def get_message(self) -> str:
1236
+ name = self.patch_1.name
1237
+ fix = self._fix_dupe_msg(
1238
+ self.patch_1.original_file_path,
1239
+ self.existing_patch_path,
1240
+ name,
1241
+ "resource",
1242
+ )
1243
+ msg = (
1244
+ f"dbt found two schema.yml entries for the same resource named "
1245
+ f"{name}. Resources and their associated columns may only be "
1246
+ f"described a single time. To fix this, {fix}"
1247
+ )
1248
+ return msg
1249
+
1250
+
1251
+ # should this inherit ParsingError instead?
1252
+ class DuplicateResourceNameError(CompilationError):
1253
+ def __init__(self, node_1, node_2):
1254
+ self.node_1 = node_1
1255
+ self.node_2 = node_2
1256
+ super().__init__(msg=self.get_message())
1257
+
1258
+ def get_message(self) -> str:
1259
+ duped_name = self.node_1.name
1260
+ node_type = NodeType(self.node_1.resource_type)
1261
+ pluralized = (
1262
+ node_type.pluralize()
1263
+ if self.node_1.resource_type == self.node_2.resource_type
1264
+ else "resources" # still raise if ref() collision, e.g. model + seed
1265
+ )
1266
+
1267
+ action = "looking for"
1268
+ # duplicate 'ref' targets
1269
+ if node_type in REFABLE_NODE_TYPES:
1270
+ formatted_name = f'ref("{duped_name}")'
1271
+ # duplicate sources
1272
+ elif node_type == NodeType.Source:
1273
+ duped_name = self.node_1.get_full_source_name()
1274
+ formatted_name = self.node_1.get_source_representation()
1275
+ # duplicate docs blocks
1276
+ elif node_type == NodeType.Documentation:
1277
+ formatted_name = f'doc("{duped_name}")'
1278
+ # duplicate generic tests
1279
+ elif node_type == NodeType.Test and hasattr(self.node_1, "test_metadata"):
1280
+ column_name = (
1281
+ f'column "{self.node_1.column_name}" in ' if self.node_1.column_name else ""
1282
+ )
1283
+ model_name = self.node_1.file_key_name
1284
+ duped_name = f'{self.node_1.name}" defined on {column_name}"{model_name}'
1285
+ action = "running"
1286
+ formatted_name = "tests"
1287
+ # all other resource types
1288
+ else:
1289
+ formatted_name = duped_name
1290
+
1291
+ msg = f"""
1292
+ dbt found two {pluralized} with the name "{duped_name}".
1293
+
1294
+ Since these resources have the same name, dbt will be unable to find the correct resource
1295
+ when {action} {formatted_name}.
1296
+
1297
+ To fix this, change the name of one of these resources:
1298
+ - {self.node_1.unique_id} ({self.node_1.original_file_path})
1299
+ - {self.node_2.unique_id} ({self.node_2.original_file_path})
1300
+ """.strip()
1301
+ return msg
1302
+
1303
+
1304
+ class DuplicateVersionedUnversionedError(ParsingError):
1305
+ def __init__(self, versioned_node, unversioned_node):
1306
+ self.versioned_node = versioned_node
1307
+ self.unversioned_node = unversioned_node
1308
+ super().__init__(msg=self.get_message())
1309
+
1310
+ def get_message(self) -> str:
1311
+ msg = f"""
1312
+ dbt found versioned and unversioned models with the name "{self.versioned_node.name}".
1313
+
1314
+ Since these resources have the same name, dbt will be unable to find the correct resource
1315
+ when looking for ref('{self.versioned_node.name}').
1316
+
1317
+ To fix this, change the name of the unversioned resource
1318
+ {self.unversioned_node.unique_id} ({self.unversioned_node.original_file_path})
1319
+ or add the unversioned model to the versions in {self.versioned_node.patch_path}
1320
+ """.strip()
1321
+ return msg
1322
+
1323
+
1324
+ class PropertyYMLError(CompilationError):
1325
+ def __init__(self, path: str, issue: str):
1326
+ self.path = path
1327
+ self.issue = issue
1328
+ super().__init__(msg=self.get_message())
1329
+
1330
+ def get_message(self) -> str:
1331
+ msg = (
1332
+ f"The yml property file at {self.path} is invalid because {self.issue}. "
1333
+ "Please consult the documentation for more information on yml property file "
1334
+ "syntax:\n\nhttps://docs.getdbt.com/reference/configs-and-properties"
1335
+ )
1336
+ return msg
1337
+
1338
+
1339
+ class ContractError(CompilationError):
1340
+ def __init__(self, yaml_columns, sql_columns):
1341
+ self.yaml_columns = yaml_columns
1342
+ self.sql_columns = sql_columns
1343
+ super().__init__(msg=self.get_message())
1344
+
1345
+ def get_mismatches(self) -> "agate.Table":
1346
+ # avoid a circular import
1347
+ from dbt_common.clients.agate_helper import table_from_data_flat
1348
+
1349
+ column_names = ["column_name", "definition_type", "contract_type", "mismatch_reason"]
1350
+ # list of mismatches
1351
+ mismatches: List[Dict[str, str]] = []
1352
+ # track sql cols so we don't need another for loop later
1353
+ sql_col_set = set()
1354
+ # for each sql col list
1355
+ for sql_col in self.sql_columns:
1356
+ # add sql col to set
1357
+ sql_col_set.add(sql_col["name"])
1358
+ # for each yaml col list
1359
+ for i, yaml_col in enumerate(self.yaml_columns):
1360
+ # if name matches
1361
+ if sql_col["name"] == yaml_col["name"]:
1362
+ # if type matches
1363
+ if sql_col["data_type"] == yaml_col["data_type"]:
1364
+ # its a perfect match! don't include in mismatch table
1365
+ break
1366
+ else:
1367
+ # same name, diff type
1368
+ row = [
1369
+ sql_col["name"],
1370
+ sql_col["data_type"],
1371
+ yaml_col["data_type"],
1372
+ "data type mismatch",
1373
+ ]
1374
+ mismatches += [dict(zip(column_names, row))]
1375
+ break
1376
+ # if last loop, then no name match
1377
+ if i == len(self.yaml_columns) - 1:
1378
+ row = [sql_col["name"], sql_col["data_type"], "", "missing in contract"]
1379
+ mismatches += [dict(zip(column_names, row))]
1380
+
1381
+ # now add all yaml cols without a match
1382
+ for yaml_col in self.yaml_columns:
1383
+ if yaml_col["name"] not in sql_col_set:
1384
+ row = [yaml_col["name"], "", yaml_col["data_type"], "missing in definition"]
1385
+ mismatches += [dict(zip(column_names, row))]
1386
+
1387
+ mismatches_sorted = sorted(mismatches, key=lambda d: d["column_name"])
1388
+ return table_from_data_flat(mismatches_sorted, column_names)
1389
+
1390
+ def get_message(self) -> str:
1391
+ if not self.yaml_columns:
1392
+ return (
1393
+ "This model has an enforced contract, and its 'columns' specification is missing"
1394
+ )
1395
+
1396
+ table: "agate.Table" = self.get_mismatches()
1397
+ # Hack to get Agate table output as string
1398
+ output = io.StringIO()
1399
+ table.print_table(output=output, max_rows=None, max_column_width=50) # type: ignore
1400
+ mismatches = output.getvalue()
1401
+
1402
+ msg = (
1403
+ "This model has an enforced contract that failed.\n"
1404
+ "Please ensure the name, data_type, and number of columns in your contract "
1405
+ "match the columns in your model's definition.\n\n"
1406
+ f"{mismatches}"
1407
+ )
1408
+
1409
+ return msg
1410
+
1411
+
1412
+ # not modifying these since rpc should be deprecated soon
1413
+ class UnknownAsyncIDException(Exception):
1414
+ CODE = 10012
1415
+ MESSAGE = "RPC server got an unknown async ID"
1416
+
1417
+ def __init__(self, task_id):
1418
+ self.task_id = task_id
1419
+
1420
+ def __str__(self):
1421
+ return f"{self.MESSAGE}: {self.task_id}"
1422
+
1423
+
1424
+ class RPCFailureResult(DbtRuntimeError):
1425
+ CODE = 10002
1426
+ MESSAGE = "RPC execution error"
1427
+
1428
+
1429
+ class RPCTimeoutException(DbtRuntimeError):
1430
+ CODE = 10008
1431
+ MESSAGE = "RPC timeout error"
1432
+
1433
+ def __init__(self, timeout: Optional[float] = None):
1434
+ super().__init__(self.MESSAGE)
1435
+ self.timeout = timeout
1436
+
1437
+ def data(self):
1438
+ result = super().data()
1439
+ result.update(
1440
+ {
1441
+ "timeout": self.timeout,
1442
+ "message": f"RPC timed out after {self.timeout}s",
1443
+ }
1444
+ )
1445
+ return result
1446
+
1447
+
1448
+ class RPCKilledException(DbtRuntimeError):
1449
+ CODE = 10009
1450
+ MESSAGE = "RPC process killed"
1451
+
1452
+ def __init__(self, signum: int):
1453
+ self.signum = signum
1454
+ self.msg = f"RPC process killed by signal {self.signum}"
1455
+ super().__init__(self.msg)
1456
+
1457
+ def data(self):
1458
+ return {
1459
+ "signum": self.signum,
1460
+ "message": self.msg,
1461
+ }
1462
+
1463
+
1464
+ class RPCCompiling(DbtRuntimeError):
1465
+ CODE = 10010
1466
+ MESSAGE = 'RPC server is compiling the project, call the "status" method for' " compile status"
1467
+
1468
+ def __init__(self, msg: Optional[str] = None, node=None):
1469
+ if msg is None:
1470
+ msg = "compile in progress"
1471
+ super().__init__(msg, node)
1472
+
1473
+
1474
+ class RPCLoadException(DbtRuntimeError):
1475
+ CODE = 10011
1476
+ MESSAGE = (
1477
+ 'RPC server failed to compile project, call the "status" method for' " compile status"
1478
+ )
1479
+
1480
+ def __init__(self, cause: Dict[str, Any]):
1481
+ self.cause = cause
1482
+ self.msg = f'{self.MESSAGE}: {self.cause["message"]}'
1483
+ super().__init__(self.msg)
1484
+
1485
+ def data(self):
1486
+ return {"cause": self.cause, "message": self.msg}