-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[dagster-dbt] add translator option to attach model files as code ref…
…erence metadata (#21888) ## Summary Adds the option to a custom `DagsterDbtTranslator` to attach code reference metadata pointing to the dbt model files for each asset. Unfortunately, this requires that we also get the `project_dir ` from the user, since that is only available at run time as part of the resource. Maybe there's a good way around this? The manifest used to have a `root_path` field, but this [was recently removed](dbt-labs/dbt-core#6171). ```python @dbt_assets( manifest=..., dagster_dbt_translator=DagsterDbtTranslator( settings=DagsterDbtTranslatorSettings(attach_sql_model_code_reference=True) ), project=DbtProject(...) ) def my_dbt_assets(): ... ``` ## Test Plan Unit tests.
- Loading branch information
Showing
3 changed files
with
206 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
130 changes: 130 additions & 0 deletions
130
python_modules/libraries/dagster-dbt/dagster_dbt_tests/core/test_code_references.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
import inspect | ||
import os | ||
from typing import Any, Dict | ||
|
||
import pytest | ||
from dagster._core.definitions.definitions_class import Definitions | ||
from dagster._core.definitions.metadata.source_code import ( | ||
LocalFileCodeReference, | ||
UrlCodeReference, | ||
link_to_source_control, | ||
with_source_code_references, | ||
) | ||
from dagster._core.errors import DagsterInvalidDefinitionError | ||
from dagster_dbt import DbtProject | ||
from dagster_dbt.asset_decorator import dbt_assets | ||
from dagster_dbt.dagster_dbt_translator import DagsterDbtTranslator, DagsterDbtTranslatorSettings | ||
|
||
from ..dbt_projects import ( | ||
test_jaffle_shop_path, | ||
) | ||
|
||
JAFFLE_SHOP_ROOT_PATH = os.path.normpath(test_jaffle_shop_path) | ||
|
||
|
||
def test_basic_attach_code_references(test_jaffle_shop_manifest: Dict[str, Any]) -> None: | ||
@dbt_assets( | ||
manifest=test_jaffle_shop_manifest, | ||
dagster_dbt_translator=DagsterDbtTranslator( | ||
settings=DagsterDbtTranslatorSettings(enable_code_references=True) | ||
), | ||
project=DbtProject(project_dir=os.fspath(test_jaffle_shop_path)), | ||
) | ||
def my_dbt_assets(): ... | ||
|
||
for asset_key, asset_metadata in my_dbt_assets.metadata_by_key.items(): | ||
assert "dagster/code_references" in asset_metadata | ||
|
||
references = asset_metadata["dagster/code_references"].code_references | ||
assert len(references) == 1 | ||
|
||
reference = references[0] | ||
assert isinstance(reference, LocalFileCodeReference) | ||
assert reference.file_path.endswith( | ||
asset_key.path[-1] + ".sql" | ||
) or reference.file_path.endswith(asset_key.path[-1] + ".csv") | ||
assert os.path.exists(reference.file_path), reference.file_path | ||
|
||
|
||
def test_basic_attach_code_references_no_project_dir( | ||
test_jaffle_shop_manifest: Dict[str, Any], | ||
) -> None: | ||
# expect exception because enable_code_references=True but no project_dir | ||
with pytest.raises(DagsterInvalidDefinitionError): | ||
|
||
@dbt_assets( | ||
manifest=test_jaffle_shop_manifest, | ||
dagster_dbt_translator=DagsterDbtTranslator( | ||
settings=DagsterDbtTranslatorSettings(enable_code_references=True) | ||
), | ||
) | ||
def my_dbt_assets(): ... | ||
|
||
|
||
def test_with_source_code_references_wrapper(test_jaffle_shop_manifest: Dict[str, Any]) -> None: | ||
@dbt_assets( | ||
manifest=test_jaffle_shop_manifest, | ||
dagster_dbt_translator=DagsterDbtTranslator( | ||
settings=DagsterDbtTranslatorSettings(enable_code_references=True) | ||
), | ||
project=DbtProject(project_dir=os.fspath(test_jaffle_shop_path)), | ||
) | ||
def my_dbt_assets(): ... | ||
|
||
defs = Definitions(assets=with_source_code_references([my_dbt_assets])) | ||
|
||
assets = defs.get_asset_graph().all_asset_keys | ||
|
||
for asset_key in assets: | ||
asset_metadata = defs.get_assets_def(asset_key).metadata_by_key[asset_key] | ||
assert "dagster/code_references" in asset_metadata | ||
|
||
references = asset_metadata["dagster/code_references"].code_references | ||
assert len(references) == 2 | ||
|
||
code_reference = references[1] | ||
assert isinstance(code_reference, LocalFileCodeReference) | ||
assert code_reference.file_path.endswith("test_code_references.py") | ||
|
||
|
||
def test_link_to_source_control_wrapper(test_jaffle_shop_manifest: Dict[str, Any]) -> None: | ||
@dbt_assets( | ||
manifest=test_jaffle_shop_manifest, | ||
dagster_dbt_translator=DagsterDbtTranslator( | ||
settings=DagsterDbtTranslatorSettings(enable_code_references=True) | ||
), | ||
project=DbtProject(project_dir=os.fspath(test_jaffle_shop_path)), | ||
) | ||
def my_dbt_assets(): ... | ||
|
||
defs = Definitions( | ||
assets=link_to_source_control( | ||
with_source_code_references([my_dbt_assets]), | ||
source_control_url="https://github.com/dagster-io/jaffle_shop", | ||
source_control_branch="master", | ||
repository_root_absolute_path=JAFFLE_SHOP_ROOT_PATH, | ||
) | ||
) | ||
|
||
assets = defs.get_asset_graph().all_asset_keys | ||
|
||
for asset_key in assets: | ||
asset_metadata = defs.get_assets_def(asset_key).metadata_by_key[asset_key] | ||
assert "dagster/code_references" in asset_metadata | ||
|
||
references = asset_metadata["dagster/code_references"].code_references | ||
assert len(references) == 2 | ||
|
||
model_reference = references[0] | ||
assert isinstance(model_reference, UrlCodeReference) | ||
assert model_reference.url.startswith( | ||
"https://github.com/dagster-io/jaffle_shop/tree/master/" | ||
) | ||
assert model_reference.url.endswith( | ||
asset_key.path[-1] + ".sql#L1" | ||
) or model_reference.url.endswith(asset_key.path[-1] + ".csv#L1") | ||
|
||
source_reference = references[1] | ||
assert isinstance(source_reference, UrlCodeReference) | ||
line_no = inspect.getsourcelines(my_dbt_assets.op.compute_fn.decorated_fn)[1] | ||
assert source_reference.url.endswith(f"test_code_references.py#L{line_no}") |