From 03cb4f5552f33241c4f07b55de41e7f43fc31ce8 Mon Sep 17 00:00:00 2001 From: Chris Rericha Date: Tue, 7 Oct 2025 15:28:44 -0400 Subject: [PATCH] Fix: Normalize canonical names and use in circular ref workaround --- sqlmesh/dbt/basemodel.py | 6 ++++-- sqlmesh/dbt/context.py | 14 ++++++++------ sqlmesh/dbt/source.py | 5 ++++- tests/dbt/test_transformation.py | 10 +++++----- 4 files changed, 21 insertions(+), 14 deletions(-) diff --git a/sqlmesh/dbt/basemodel.py b/sqlmesh/dbt/basemodel.py index 0c719ebb88..68e350eb3c 100644 --- a/sqlmesh/dbt/basemodel.py +++ b/sqlmesh/dbt/basemodel.py @@ -222,7 +222,9 @@ def canonical_name(self, context: DbtContext) -> str: ) if relation.database == context.target.database: relation = relation.include(database=False) - self._canonical_name = relation.render() + self._canonical_name = d.normalize_model_name( + relation.render(), context.target.database, context.default_dialect + ) return self._canonical_name @property @@ -334,7 +336,7 @@ def sqlmesh_model_kwargs( { source.canonical_name(context) for source in model_context.sources.values() - if source.fqn not in context.model_fqns + if source.canonical_name(context) not in context.model_canonical_names # Allow dbt projects to reference a model as a source without causing a cycle }, ), diff --git a/sqlmesh/dbt/context.py b/sqlmesh/dbt/context.py index bcdae8f97a..1c347f54ff 100644 --- a/sqlmesh/dbt/context.py +++ b/sqlmesh/dbt/context.py @@ -51,7 +51,7 @@ class DbtContext: _project_name: t.Optional[str] = None _variables: t.Dict[str, t.Any] = field(default_factory=dict) _models: t.Dict[str, ModelConfig] = field(default_factory=dict) - _model_fqns: t.Set[str] = field(default_factory=set) + _model_canonical_names: t.Set[str] = field(default_factory=set) _seeds: t.Dict[str, SeedConfig] = field(default_factory=dict) _sources: t.Dict[str, SourceConfig] = field(default_factory=dict) _refs: t.Dict[str, t.Union[ModelConfig, SeedConfig]] = field(default_factory=dict) @@ -145,7 +145,7 @@ def models(self) -> t.Dict[str, ModelConfig]: def models(self, models: t.Dict[str, ModelConfig]) -> None: self._models = {} self._refs = {} - self._model_fqns = set() + self._model_canonical_names = set() self.add_models(models) def add_models(self, models: t.Dict[str, ModelConfig]) -> None: @@ -154,10 +154,12 @@ def add_models(self, models: t.Dict[str, ModelConfig]) -> None: self._jinja_environment = None @property - def model_fqns(self) -> t.Set[str]: - if not self._model_fqns: - self._model_fqns = {model.fqn for model in self._models.values()} - return self._model_fqns + def model_canonical_names(self) -> t.Set[str]: + if not self._model_canonical_names: + self._model_canonical_names = { + model.canonical_name(self) for model in self._models.values() + } + return self._model_canonical_names @property def seeds(self) -> t.Dict[str, SeedConfig]: diff --git a/sqlmesh/dbt/source.py b/sqlmesh/dbt/source.py index efafbf1642..60f6136852 100644 --- a/sqlmesh/dbt/source.py +++ b/sqlmesh/dbt/source.py @@ -4,6 +4,7 @@ from pydantic import Field +from sqlmesh.core import dialect as d from sqlmesh.core.config.base import UpdateStrategy from sqlmesh.dbt.column import ColumnConfig from sqlmesh.dbt.common import GeneralConfig @@ -89,7 +90,9 @@ def canonical_name(self, context: DbtContext) -> str: ) if relation.database == context.target.database: relation = relation.include(database=False) - self._canonical_name = relation.render() + self._canonical_name = d.normalize_model_name( + relation.render(), context.target.database, context.default_dialect + ) return self._canonical_name @property diff --git a/tests/dbt/test_transformation.py b/tests/dbt/test_transformation.py index dd69f46200..bb0ce3d93b 100644 --- a/tests/dbt/test_transformation.py +++ b/tests/dbt/test_transformation.py @@ -2687,23 +2687,23 @@ def test_ignore_source_depends_on_when_also_model(dbt_dummy_postgres_config: Pos source_a = SourceConfig( name="source_a", - fqn=["package", "schema", "model_a"], ) - source_a._canonical_name = "schema.source_a" + source_a._canonical_name = "schema.model_a" source_b = SourceConfig( name="source_b", - fqn=["package", "schema", "source_b"], ) source_b._canonical_name = "schema.source_b" context.sources = {"source_a": source_a, "source_b": source_b} model = ModelConfig( dependencies=Dependencies(sources={"source_a", "source_b"}), - fqn=["package", "schema", "test_model"], ) + model._canonical_name = "schema.test_model" + model_a = ModelConfig(name="model_a") + model_a._canonical_name = "schema.model_a" context.models = { "test_model": model, - "model_a": ModelConfig(name="model_a", fqn=["package", "schema", "model_a"]), + "model_a": model_a, } assert model.sqlmesh_model_kwargs(context)["depends_on"] == {"schema.source_b"}