Skip to content

Commit 46be991

Browse files
committed
fix: ignore grants for model kinds that don't support it
1 parent 17e71c9 commit 46be991

File tree

5 files changed

+54
-7
lines changed

5 files changed

+54
-7
lines changed

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
@@ -650,11 +650,12 @@ def to_sqlmesh(
650650
if physical_properties:
651651
model_kwargs["physical_properties"] = physical_properties
652652

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

657-
kind = self.model_kind(context)
658659
allow_partials = model_kwargs.pop("allow_partials", None)
659660
if allow_partials is None:
660661
# 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,
@@ -11850,6 +11852,17 @@ def test_grants_invalid_model_kind_errors(kind: str):
1185011852
)
1185111853

1185211854

11855+
def test_model_kind_supports_grants():
11856+
assert FullKind().supports_grants is True
11857+
assert ViewKind().supports_grants is True
11858+
assert IncrementalByTimeRangeKind(time_column="ds").supports_grants is True
11859+
assert IncrementalByUniqueKeyKind(unique_key=["id"]).supports_grants is True
11860+
assert SCDType2ByTimeKind(unique_key=["id"]).supports_grants is True
11861+
11862+
assert EmbeddedKind().supports_grants is False
11863+
assert ExternalKind().supports_grants is False
11864+
11865+
1185311866
def test_grants_validation_no_grants():
1185411867
model = create_sql_model("db.table", parse_one("SELECT 1 AS id"), kind="FULL")
1185511868
assert model.grants is None

tests/dbt/test_model.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1026,3 +1026,34 @@ def test_model_grants_engine_specific_bigquery() -> None:
10261026
assert grants_config is not None
10271027
assert grants_config["bigquery.dataviewer"] == ["user@domain.com"]
10281028
assert grants_config["select"] == ["analyst@company.com"]
1029+
1030+
1031+
def test_ephemeral_model_with_global_grants(create_empty_project):
1032+
dbt_project_dir, dbt_model_dir = create_empty_project()
1033+
1034+
yaml = YAML()
1035+
dbt_project_config = {
1036+
"name": "test_project",
1037+
"version": "1.0.0",
1038+
"config-version": 2,
1039+
"profile": "test",
1040+
"model-paths": ["models"],
1041+
"models": {"test_project": {"grants": {"select": ["reporter", "analyst"]}}},
1042+
}
1043+
dbt_project_file = dbt_project_dir / "dbt_project.yml"
1044+
with open(dbt_project_file, "w", encoding="utf-8") as f:
1045+
yaml.dump(dbt_project_config, f)
1046+
1047+
ephemeral_model_sql = """
1048+
{{ config(materialized='ephemeral') }}
1049+
SELECT 1 as id
1050+
"""
1051+
ephemeral_model_file = dbt_model_dir / "ephemeral_model.sql"
1052+
with open(ephemeral_model_file, "w", encoding="utf-8") as f:
1053+
f.write(ephemeral_model_sql)
1054+
1055+
context = Context(paths=dbt_project_dir)
1056+
model = context.get_model('"local"."main"."ephemeral_model"')
1057+
1058+
assert model.kind.is_embedded
1059+
assert model.grants is None # grants config is skipped for ephemeral / embedded models

0 commit comments

Comments
 (0)