10
10
from dbt_artifacts_parser .parser import parse_run_results , parse_manifest
11
11
from dbt .config .renderer import ProfileRenderer
12
12
13
+ from data_diff .errors import (
14
+ DataDiffDbtBigQueryOauthOnlyError ,
15
+ DataDiffDbtConnectionNotImplementedError ,
16
+ DataDiffDbtCoreNoRunnerError ,
17
+ DataDiffDbtNoSuccessfulModelsInRunError ,
18
+ DataDiffDbtProfileNotFoundError ,
19
+ DataDiffDbtProjectVarsNotFoundError ,
20
+ DataDiffDbtRedshiftPasswordOnlyError ,
21
+ DataDiffDbtRunResultsVersionError ,
22
+ DataDiffDbtSelectNoMatchingModelsError ,
23
+ DataDiffDbtSelectUnexpectedError ,
24
+ DataDiffDbtSelectVersionTooLowError ,
25
+ DataDiffDbtSnowflakeSetConnectionError ,
26
+ )
27
+
13
28
from .utils import getLogger , get_from_dict_with_raise
14
29
15
30
@@ -91,9 +106,11 @@ def __init__(self, profiles_dir_override: str, project_dir_override: str) -> Non
91
106
92
107
def get_datadiff_variables (self ) -> dict :
93
108
doc_url = "https://docs.datafold.com/development_testing/open_source#configure-your-dbt-project"
94
- error_message = f"vars: data_diff: section not found in dbt_project.yml.\n \n To solve this, please configure your dbt project: \n { doc_url } \n "
95
- vars = get_from_dict_with_raise (self .project_dict , "vars" , error_message )
96
- return get_from_dict_with_raise (vars , "data_diff" , error_message )
109
+ exception = DataDiffDbtProjectVarsNotFoundError (
110
+ f"vars: data_diff: section not found in dbt_project.yml.\n \n To solve this, please configure your dbt project: \n { doc_url } \n "
111
+ )
112
+ vars_dict = get_from_dict_with_raise (self .project_dict , "vars" , exception )
113
+ return get_from_dict_with_raise (vars_dict , "data_diff" , exception )
97
114
98
115
def get_datadiff_model_config (self , model_meta : dict ) -> TDatadiffModelConfig :
99
116
where_filter = None
@@ -118,11 +135,11 @@ def get_models(self, dbt_selection: Optional[str] = None):
118
135
return self .get_dbt_selection_models (dbt_selection )
119
136
# edge case if running data-diff from a separate env than dbt (likely local development)
120
137
else :
121
- raise Exception (
138
+ raise DataDiffDbtCoreNoRunnerError (
122
139
"data-diff is using a dbt-core version < 1.5, update the environment's dbt-core version via pip install 'dbt-core>=1.5' in order to use `--select`"
123
140
)
124
141
else :
125
- raise Exception (
142
+ raise DataDiffDbtSelectVersionTooLowError (
126
143
f"The `--select` feature requires dbt >= 1.5, but your project's manifest.json is from dbt v{ dbt_version } . Please follow these steps to use the `--select` feature: \n 1. Update your dbt-core version via pip install 'dbt-core>=1.5'. Details: https://docs.getdbt.com/docs/core/pip-install#change-dbt-core-versions \n 2. Execute any `dbt` command (`run`, `compile`, `build`) to create a new manifest.json."
127
144
)
128
145
else :
@@ -152,15 +169,17 @@ def get_dbt_selection_models(self, dbt_selection: str) -> List[str]:
152
169
)
153
170
if results .exception :
154
171
raise results .exception
155
- elif results .success and results .result :
172
+
173
+ if results .success and results .result :
156
174
model_list = [json .loads (model )["unique_id" ] for model in results .result ]
157
175
models = [self .manifest_obj .nodes .get (x ) for x in model_list ]
158
176
return models
159
- elif not results .result :
160
- raise Exception (f"No dbt models found for `--select { dbt_selection } `" )
161
- else :
162
- logger .debug (str (results ))
163
- raise Exception ("Encountered an unexpected error while finding `--select` models" )
177
+
178
+ if not results .result :
179
+ raise DataDiffDbtSelectNoMatchingModelsError (f"No dbt models found for `--select { dbt_selection } `" )
180
+
181
+ logger .debug (str (results ))
182
+ raise DataDiffDbtSelectUnexpectedError ("Encountered an unexpected error while finding `--select` models" )
164
183
165
184
def get_run_results_models (self ):
166
185
with open (self .project_dir / RUN_RESULTS_PATH ) as run_results :
@@ -174,16 +193,18 @@ def get_run_results_models(self):
174
193
self .profiles_dir = legacy_profiles_dir ()
175
194
176
195
if dbt_version < parse_version (LOWER_DBT_V ):
177
- raise Exception (f"Found dbt: v{ dbt_version } Expected the dbt project's version to be >= { LOWER_DBT_V } " )
178
- elif dbt_version >= parse_version (UPPER_DBT_V ):
196
+ raise DataDiffDbtRunResultsVersionError (
197
+ f"Found dbt: v{ dbt_version } Expected the dbt project's version to be >= { LOWER_DBT_V } "
198
+ )
199
+ if dbt_version >= parse_version (UPPER_DBT_V ):
179
200
logger .warning (
180
201
f"{ dbt_version } is a recent version of dbt and may not be fully tested with data-diff! \n Please report any issues to https://github.com/datafold/data-diff/issues"
181
202
)
182
203
183
204
success_models = [x .unique_id for x in run_results_obj .results if x .status .name == "success" ]
184
205
models = [self .manifest_obj .nodes .get (x ) for x in success_models ]
185
206
if not models :
186
- raise ValueError ("Expected > 0 successful models runs from the last dbt command." )
207
+ raise DataDiffDbtNoSuccessfulModelsInRunError ("Expected > 0 successful models runs from the last dbt command." )
187
208
188
209
return models
189
210
@@ -209,25 +230,35 @@ def get_connection_creds(self) -> Tuple[Dict[str, str], str]:
209
230
dbt_profile_var = self .project_dict .get ("profile" )
210
231
211
232
profile = get_from_dict_with_raise (
212
- profiles , dbt_profile_var , f"No profile '{ dbt_profile_var } ' found in '{ profiles_path } '."
233
+ profiles ,
234
+ dbt_profile_var ,
235
+ DataDiffDbtProfileNotFoundError (f"No profile '{ dbt_profile_var } ' found in '{ profiles_path } '." ),
213
236
)
214
237
# values can contain env_vars
215
238
rendered_profile = ProfileRenderer ().render_data (profile )
216
239
profile_target = get_from_dict_with_raise (
217
- rendered_profile , "target" , f"No target found in profile '{ dbt_profile_var } ' in '{ profiles_path } '."
240
+ rendered_profile ,
241
+ "target" ,
242
+ DataDiffDbtProfileNotFoundError (f"No target found in profile '{ dbt_profile_var } ' in '{ profiles_path } '." ),
218
243
)
219
244
outputs = get_from_dict_with_raise (
220
- rendered_profile , "outputs" , f"No outputs found in profile '{ dbt_profile_var } ' in '{ profiles_path } '."
245
+ rendered_profile ,
246
+ "outputs" ,
247
+ DataDiffDbtProfileNotFoundError (f"No outputs found in profile '{ dbt_profile_var } ' in '{ profiles_path } '." ),
221
248
)
222
249
credentials = get_from_dict_with_raise (
223
250
outputs ,
224
251
profile_target ,
225
- f"No credentials found for target '{ profile_target } ' in profile '{ dbt_profile_var } ' in '{ profiles_path } '." ,
252
+ DataDiffDbtProfileNotFoundError (
253
+ f"No credentials found for target '{ profile_target } ' in profile '{ dbt_profile_var } ' in '{ profiles_path } '."
254
+ ),
226
255
)
227
256
conn_type = get_from_dict_with_raise (
228
257
credentials ,
229
258
"type" ,
230
- f"No type found for target '{ profile_target } ' in profile '{ dbt_profile_var } ' in '{ profiles_path } '." ,
259
+ DataDiffDbtProfileNotFoundError (
260
+ f"No type found for target '{ profile_target } ' in profile '{ dbt_profile_var } ' in '{ profiles_path } '."
261
+ ),
231
262
)
232
263
conn_type = conn_type .lower ()
233
264
@@ -253,7 +284,7 @@ def set_connection(self):
253
284
254
285
if credentials .get ("private_key_path" ) is not None :
255
286
if credentials .get ("password" ) is not None :
256
- raise Exception ("Cannot use password and key at the same time" )
287
+ raise DataDiffDbtSnowflakeSetConnectionError ("Cannot use password and key at the same time" )
257
288
conn_info ["key" ] = credentials .get ("private_key_path" )
258
289
conn_info ["private_key_passphrase" ] = credentials .get ("private_key_passphrase" )
259
290
elif credentials .get ("authenticator" ) is not None :
@@ -262,13 +293,13 @@ def set_connection(self):
262
293
elif credentials .get ("password" ) is not None :
263
294
conn_info ["password" ] = credentials .get ("password" )
264
295
else :
265
- raise Exception ("Snowflake: unsupported auth method" )
296
+ raise DataDiffDbtSnowflakeSetConnectionError ("Snowflake: unsupported auth method" )
266
297
elif conn_type == "bigquery" :
267
298
method = credentials .get ("method" )
268
299
# there are many connection types https://docs.getdbt.com/reference/warehouse-setups/bigquery-setup#oauth-via-gcloud
269
300
# this assumes that the user is auth'd via `gcloud auth application-default login`
270
301
if method is None or method != "oauth" :
271
- raise Exception ("Oauth is the current method supported for Big Query." )
302
+ raise DataDiffDbtBigQueryOauthOnlyError ("Oauth is the current method supported for Big Query." )
272
303
conn_info = {
273
304
"driver" : conn_type ,
274
305
"project" : credentials .get ("project" ),
@@ -284,7 +315,7 @@ def set_connection(self):
284
315
if (credentials .get ("pass" ) is None and credentials .get ("password" ) is None ) or credentials .get (
285
316
"method"
286
317
) == "iam" :
287
- raise Exception ("Only password authentication is currently supported for Redshift." )
318
+ raise DataDiffDbtRedshiftPasswordOnlyError ("Only password authentication is currently supported for Redshift." )
288
319
conn_info = {
289
320
"driver" : conn_type ,
290
321
"host" : credentials .get ("host" ),
@@ -315,7 +346,7 @@ def set_connection(self):
315
346
}
316
347
self .threads = credentials .get ("threads" )
317
348
else :
318
- raise NotImplementedError (f"Provider { conn_type } is not yet supported for dbt diffs" )
349
+ raise DataDiffDbtConnectionNotImplementedError (f"Provider { conn_type } is not yet supported for dbt diffs" )
319
350
320
351
self .connection = conn_info
321
352
0 commit comments