Skip to content
This repository was archived by the owner on May 17, 2024. It is now read-only.

Commit 24abee4

Browse files
committed
provide an opportunity to parse db credentials from dbt profiles.yml
1 parent acd1643 commit 24abee4

3 files changed

Lines changed: 341 additions & 14 deletions

File tree

data_diff/cloud/data_source.py

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import enum
21
import time
32
from typing import List, Optional
43

@@ -14,6 +13,7 @@
1413
TDsConfig,
1514
TestDataSourceStatus,
1615
)
16+
from ..dbt_parser import DbtParser
1717

1818

1919
UNKNOWN_VALUE = "unknown_value"
@@ -49,8 +49,12 @@ def _validate_temp_schema(temp_schema: str):
4949
raise ValueError("Temporary schema should have a format <database>.<schema>")
5050

5151

52-
def create_ds_config(ds_config: TCloudApiDataSourceConfigSchema, data_source_name: str) -> TDsConfig:
53-
options = _parse_ds_credentials(ds_config=ds_config, only_basic_settings=True)
52+
def create_ds_config(
53+
ds_config: TCloudApiDataSourceConfigSchema,
54+
data_source_name: str,
55+
dbt_parser: Optional[DbtParser] = None,
56+
) -> TDsConfig:
57+
options = _parse_ds_credentials(ds_config=ds_config, only_basic_settings=True, dbt_parser=dbt_parser)
5458

5559
temp_schema = TemporarySchemaPrompt.ask("Temporary schema (<database>.<schema>)")
5660
float_tolerance = FloatPrompt.ask("Float tolerance", default=0.000001)
@@ -64,7 +68,25 @@ def create_ds_config(ds_config: TCloudApiDataSourceConfigSchema, data_source_nam
6468
)
6569

6670

67-
def _parse_ds_credentials(ds_config: TCloudApiDataSourceConfigSchema, only_basic_settings: bool = True):
71+
def _parse_ds_credentials(
72+
ds_config: TCloudApiDataSourceConfigSchema, only_basic_settings: bool = True, dbt_parser: Optional[DbtParser] = None
73+
):
74+
def cast_value(value: str, type_: str):
75+
if type_ == "integer":
76+
return int(value)
77+
elif type_ == "boolean":
78+
return bool(value)
79+
return value
80+
81+
creds = {}
82+
use_dbt_data = False
83+
if dbt_parser is not None:
84+
use_dbt_data = Confirm.ask("Would you like to extract database credentials from dbt profile.yml?")
85+
try:
86+
creds = dbt_parser.get_connection_creds()[0]
87+
except Exception as e:
88+
rich.print(f"[red]Cannot parse database credentials from dbt profile.yml. Reason: {e}")
89+
6890
ds_options = {}
6991
basic_required_fields = set(ds_config.config_schema.required)
7092
for param_name, param_data in ds_config.config_schema.properties.items():
@@ -83,6 +105,14 @@ def _parse_ds_credentials(ds_config: TCloudApiDataSourceConfigSchema, only_basic
83105
if default_value != UNKNOWN_VALUE:
84106
input_values["default"] = default_value
85107

108+
if use_dbt_data:
109+
value = creds.get(param_name, UNKNOWN_VALUE)
110+
if value == UNKNOWN_VALUE:
111+
rich.print(f'[red]Cannot extract "{param_name}" from dbt profile.yml. Please, type it manually')
112+
else:
113+
ds_options[param_name] = cast_value(value, type_)
114+
continue
115+
86116
if type_ == "integer":
87117
value = IntPrompt.ask(**input_values)
88118
elif type_ == "boolean":
@@ -177,7 +207,7 @@ def _render_data_source_test_results(test_results: List[TDataSourceTestStage]) -
177207
rich.print(table)
178208

179209

180-
def get_or_create_data_source(api: DatafoldAPI) -> int:
210+
def get_or_create_data_source(api: DatafoldAPI, dbt_parser: Optional[DbtParser] = None) -> int:
181211
ds_configs = api.get_data_source_schema_config()
182212
data_sources = api.get_data_sources()
183213

@@ -198,10 +228,10 @@ def get_or_create_data_source(api: DatafoldAPI) -> int:
198228
_render_data_source(data_source=ds, title=f'Found existing data source for name "{ds.name}"')
199229
use_existing_ds = Confirm.ask("Would you like to continue with the existing data source?")
200230
if not use_existing_ds:
201-
return get_or_create_data_source(api=api)
231+
return get_or_create_data_source(api=api, dbt_parser=dbt_parser)
202232
return ds.id
203233

204-
ds_config = create_ds_config(ds_config, ds_name)
234+
ds_config = create_ds_config(ds_config=ds_config, data_source_name=ds_name, dbt_parser=dbt_parser)
205235
ds = api.create_data_source(ds_config)
206236
data_source_url = f"{api.host}/settings/integrations/dwh/{ds.type}/{ds.id}"
207237
_render_data_source(data_source=ds, title=f"Created a new data source with ID = {ds.id} ({data_source_url})")

data_diff/dbt.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,19 @@
1-
import json
21
import os
32
import time
43
import webbrowser
54
import rich
65
from rich.prompt import Confirm
76

8-
from collections import defaultdict
97
from dataclasses import dataclass
10-
from packaging.version import parse as parse_version
11-
from typing import List, Optional, Dict, Tuple, Set
8+
from typing import List, Optional, Dict
129
from .utils import dbt_diff_string_template, getLogger
13-
from .version import __version__
1410
from pathlib import Path
1511

1612
import keyring
1713

1814
from .cloud import DatafoldAPI, TCloudApiDataDiff, get_or_create_data_source
15+
from .dbt_parser import DbtParser
16+
1917

2018
logger = getLogger(__name__)
2119

@@ -41,7 +39,7 @@ def import_dbt():
4139
send_event_json,
4240
is_tracking_enabled,
4341
)
44-
from .utils import get_from_dict_with_raise, run_as_daemon, truncate_error
42+
from .utils import run_as_daemon, truncate_error
4543
from . import connect_to_table, diff_tables, Algorithm
4644

4745
RUN_RESULTS_PATH = "target/run_results.json"
@@ -105,7 +103,7 @@ def dbt_diff(
105103
rich.print("[red]Data source ID not found in dbt_project.yml")
106104
is_create_data_source = Confirm.ask("Would you like to create a new data source?")
107105
if is_create_data_source:
108-
datasource_id = get_or_create_data_source(api=api)
106+
datasource_id = get_or_create_data_source(api=api, dbt_parser=dbt_parser)
109107
rich.print(f'To use the data source in next runs, please, update your "{PROJECT_FILE}" with a block:')
110108
rich.print(f"[green]vars:\n data_diff:\n datasource_id: {datasource_id}\n")
111109
rich.print(

0 commit comments

Comments
 (0)