Skip to content

Commit b8dfb0b

Browse files
committed
fix: ignore grants for model kinds that don't support it
1 parent 1cd32c4 commit b8dfb0b

5 files changed

Lines changed: 54 additions & 7 deletions

File tree

sqlmesh/core/model/kind.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,11 @@ def full_history_restatement_only(self) -> bool:
150150
def supports_python_models(self) -> bool:
151151
return True
152152

153+
@property
154+
def supports_grants(self) -> bool:
155+
"""Whether this model kind supports grants configuration."""
156+
return self.is_materialized or self.is_view
157+
153158

154159
class ModelKindName(str, ModelKindMixin, Enum):
155160
"""The kind of model, determining how this data is computed and stored in the warehouse."""

sqlmesh/core/model/meta.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -446,11 +446,8 @@ def _root_validator(self) -> Self:
446446
)
447447

448448
# Validate grants configuration for model kind support
449-
if self.grants is not None:
450-
if kind.is_symbolic:
451-
raise ValueError(f"grants cannot be set for {kind.name} models")
452-
elif not (kind.is_materialized or kind.is_view):
453-
raise ValueError(f"grants field is not supported for {kind.name} models")
449+
if self.grants is not None and not kind.supports_grants:
450+
raise ValueError(f"grants cannot be set for {kind.name} models")
454451

455452
return self
456453

sqlmesh/dbt/model.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -651,11 +651,12 @@ def to_sqlmesh(
651651
if physical_properties:
652652
model_kwargs["physical_properties"] = physical_properties
653653

654+
kind = self.model_kind(context)
655+
654656
# A falsy grants config (None or {}) is considered as unmanaged per dbt semantics
655-
if self.grants:
657+
if self.grants and kind.supports_grants:
656658
model_kwargs["grants"] = self.grants
657659

658-
kind = self.model_kind(context)
659660
allow_partials = model_kwargs.pop("allow_partials", None)
660661
if allow_partials is None:
661662
# Set allow_partials to True for dbt models to preserve the original semantics.

tests/core/test_model.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@
5353
TimeColumn,
5454
ExternalKind,
5555
ViewKind,
56+
EmbeddedKind,
57+
SCDType2ByTimeKind,
5658
create_external_model,
5759
create_seed_model,
5860
create_sql_model,
@@ -11880,6 +11882,17 @@ def test_grants_invalid_model_kind_errors(kind: str):
1188011882
)
1188111883

1188211884

11885+
def test_model_kind_supports_grants():
11886+
assert FullKind().supports_grants is True
11887+
assert ViewKind().supports_grants is True
11888+
assert IncrementalByTimeRangeKind(time_column="ds").supports_grants is True
11889+
assert IncrementalByUniqueKeyKind(unique_key=["id"]).supports_grants is True
11890+
assert SCDType2ByTimeKind(unique_key=["id"]).supports_grants is True
11891+
11892+
assert EmbeddedKind().supports_grants is False
11893+
assert ExternalKind().supports_grants is False
11894+
11895+
1188311896
def test_grants_validation_no_grants():
1188411897
model = create_sql_model("db.table", parse_one("SELECT 1 AS id"), kind="FULL")
1188511898
assert model.grants is None

tests/dbt/test_model.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1047,3 +1047,34 @@ def test_model_grants_engine_specific_bigquery() -> None:
10471047
assert grants_config is not None
10481048
assert grants_config["bigquery.dataviewer"] == ["user@domain.com"]
10491049
assert grants_config["select"] == ["analyst@company.com"]
1050+
1051+
1052+
def test_ephemeral_model_with_global_grants(create_empty_project):
1053+
dbt_project_dir, dbt_model_dir = create_empty_project()
1054+
1055+
yaml = YAML()
1056+
dbt_project_config = {
1057+
"name": "test_project",
1058+
"version": "1.0.0",
1059+
"config-version": 2,
1060+
"profile": "test",
1061+
"model-paths": ["models"],
1062+
"models": {"test_project": {"grants": {"select": ["reporter", "analyst"]}}},
1063+
}
1064+
dbt_project_file = dbt_project_dir / "dbt_project.yml"
1065+
with open(dbt_project_file, "w", encoding="utf-8") as f:
1066+
yaml.dump(dbt_project_config, f)
1067+
1068+
ephemeral_model_sql = """
1069+
{{ config(materialized='ephemeral') }}
1070+
SELECT 1 as id
1071+
"""
1072+
ephemeral_model_file = dbt_model_dir / "ephemeral_model.sql"
1073+
with open(ephemeral_model_file, "w", encoding="utf-8") as f:
1074+
f.write(ephemeral_model_sql)
1075+
1076+
context = Context(paths=dbt_project_dir)
1077+
model = context.get_model('"local"."main"."ephemeral_model"')
1078+
1079+
assert model.kind.is_embedded
1080+
assert model.grants is None # grants config is skipped for ephemeral / embedded models

0 commit comments

Comments
 (0)