Skip to content

Commit

Permalink
Backport "Fix #8509: Support doc blocks in nested semantic model YAML… (
Browse files Browse the repository at this point in the history
  • Loading branch information
aranke authored Sep 27, 2023
1 parent 5010e87 commit 913d034
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 1 deletion.
6 changes: 6 additions & 0 deletions .changes/unreleased/Fixes-20230926-001527.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
kind: Fixes
body: Support doc blocks in nested semantic model YAML
time: 2023-09-26T00:15:27.328363+01:00
custom:
Author: aranke
Issue: "8509"
30 changes: 30 additions & 0 deletions core/dbt/parser/manifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
ResultNode,
ModelNode,
NodeRelation,
SemanticModel,
)
from dbt.contracts.graph.unparsed import NodeVersion
from dbt.contracts.util import Writable
Expand Down Expand Up @@ -1169,6 +1170,16 @@ def process_docs(self, config: RuntimeConfig):
config.project_name,
)
_process_docs_for_metrics(ctx, metric)
for semantic_model in self.manifest.semantic_models.values():
if semantic_model.created_at < self.started_at:
continue
ctx = generate_runtime_docs_context(
config,
semantic_model,
self.manifest,
config.project_name,
)
_process_docs_for_semantic_model(ctx, semantic_model)

# Loops through all nodes and exposures, for each element in
# 'sources' array finds the source node and updates the
Expand Down Expand Up @@ -1398,6 +1409,25 @@ def _process_docs_for_metrics(context: Dict[str, Any], metric: Metric) -> None:
metric.description = get_rendered(metric.description, context)


def _process_docs_for_semantic_model(
context: Dict[str, Any], semantic_model: SemanticModel
) -> None:
if semantic_model.description:
semantic_model.description = get_rendered(semantic_model.description, context)

for dimension in semantic_model.dimensions:
if dimension.description:
dimension.description = get_rendered(dimension.description, context)

for measure in semantic_model.measures:
if measure.description:
measure.description = get_rendered(measure.description, context)

for entity in semantic_model.entities:
if entity.description:
entity.description = get_rendered(entity.description, context)


def _process_refs(
manifest: Manifest, current_project: str, node, dependencies: Optional[Mapping[str, Project]]
) -> None:
Expand Down
2 changes: 1 addition & 1 deletion core/dbt/parser/schema_renderer.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def _is_norender_key(self, keypath: Keypath) -> bool:

if (
len(keypath) >= 3
and keypath[0] == "columns"
and keypath[0] in ("columns", "dimensions", "measures", "entities")
and keypath[2] in ("tests", "description")
):
return True
Expand Down
38 changes: 38 additions & 0 deletions tests/functional/semantic_models/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,44 @@
agg_time_dimension: created_at
"""

semantic_model_descriptions = """
{% docs semantic_model_description %} foo {% enddocs %}
{% docs dimension_description %} bar {% enddocs %}
{% docs measure_description %} baz {% enddocs %}
{% docs entity_description %} qux {% enddocs %}
"""

semantic_model_people_yml_with_docs = """
version: 2
semantic_models:
- name: semantic_people
model: ref('people')
description: "{{ doc('semantic_model_description') }}"
dimensions:
- name: favorite_color
type: categorical
description: "{{ doc('dimension_description') }}"
- name: created_at
type: TIME
type_params:
time_granularity: day
measures:
- name: years_tenure
agg: SUM
expr: tenure
description: "{{ doc('measure_description') }}"
- name: people
agg: count
expr: id
entities:
- name: id
description: "{{ doc('entity_description') }}"
type: primary
defaults:
agg_time_dimension: created_at
"""

enabled_semantic_model_people_yml = """
version: 2
Expand Down
73 changes: 73 additions & 0 deletions tests/functional/semantic_models/test_semantic_models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import pytest

from dbt.contracts.graph.manifest import Manifest
from dbt.exceptions import CompilationError
from dbt.tests.util import run_dbt
from tests.functional.semantic_models.fixtures import (
models_people_sql,
simple_metricflow_time_spine_sql,
semantic_model_people_yml,
models_people_metrics_yml,
semantic_model_people_yml_with_docs,
semantic_model_descriptions,
)


class TestSemanticModelDependsOn:
@pytest.fixture(scope="class")
def models(self):
return {
"people.sql": models_people_sql,
"metricflow_time_spine.sql": simple_metricflow_time_spine_sql,
"semantic_models.yml": semantic_model_people_yml,
"people_metrics.yml": models_people_metrics_yml,
}

def test_depends_on(self, project):
manifest = run_dbt(["parse"])
assert isinstance(manifest, Manifest)

expected_depends_on_for_people_semantic_model = ["model.test.people"]

number_of_people_metric = manifest.semantic_models["semantic_model.test.semantic_people"]
assert (
number_of_people_metric.depends_on.nodes
== expected_depends_on_for_people_semantic_model
)


class TestSemanticModelNestedDocs:
@pytest.fixture(scope="class")
def models(self):
return {
"people.sql": models_people_sql,
"metricflow_time_spine.sql": simple_metricflow_time_spine_sql,
"semantic_models.yml": semantic_model_people_yml_with_docs,
"people_metrics.yml": models_people_metrics_yml,
"docs.md": semantic_model_descriptions,
}

def test_depends_on(self, project):
manifest = run_dbt(["parse"])
node = manifest.semantic_models["semantic_model.test.semantic_people"]

assert node.description == "foo"
assert node.dimensions[0].description == "bar"
assert node.measures[0].description == "baz"
assert node.entities[0].description == "qux"


class TestSemanticModelUnknownModel:
@pytest.fixture(scope="class")
def models(self):
return {
"not_people.sql": models_people_sql,
"metricflow_time_spine.sql": simple_metricflow_time_spine_sql,
"semantic_models.yml": semantic_model_people_yml,
"people_metrics.yml": models_people_metrics_yml,
}

def test_unknown_model_raises_issue(self, project):
with pytest.raises(CompilationError) as excinfo:
run_dbt(["parse"])
assert "depends on a node named 'people' which was not found" in str(excinfo.value)

0 comments on commit 913d034

Please sign in to comment.