Skip to content

Commit 0b1d124

Browse files
committed
move virtual_environment_model attribute into model meta
1 parent 68d0215 commit 0b1d124

10 files changed

Lines changed: 61 additions & 33 deletions

File tree

sqlmesh/core/context.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2909,7 +2909,6 @@ def _nodes_to_snapshots(self, nodes: t.Dict[str, Node]) -> t.Dict[str, Snapshot]
29092909
config = self.config_for_node(node)
29102910
kwargs["ttl"] = config.snapshot_ttl
29112911
kwargs["table_naming_convention"] = config.physical_table_naming_convention
2912-
kwargs["virtual_environment_mode"] = config.virtual_environment_mode
29132912

29142913
snapshot = Snapshot.from_node(
29152914
node,

sqlmesh/core/loader.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,7 @@ def _load_sql_models(
603603
infer_names=self.config.model_naming.infer_names,
604604
signal_definitions=signals,
605605
default_catalog_per_gateway=self.context.default_catalog_per_gateway,
606+
virtual_environment_mode=self.config.virtual_environment_mode,
606607
**loading_default_kwargs or {},
607608
)
608609

@@ -683,6 +684,7 @@ def _load_python_models(
683684
audit_definitions=audits,
684685
signal_definitions=signals,
685686
default_catalog_per_gateway=self.context.default_catalog_per_gateway,
687+
virtual_environment_mode=self.config.virtual_environment_mode,
686688
):
687689
if model.enabled:
688690
models[model.fqn] = model

sqlmesh/core/model/decorator.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from sqlglot import exp
99
from sqlglot.dialects.dialect import DialectType
1010

11+
from sqlmesh.core.config.common import VirtualEnvironmentMode
1112
from sqlmesh.core.macros import MacroRegistry
1213
from sqlmesh.core.signal import SignalRegistry
1314
from sqlmesh.utils.jinja import JinjaMacroRegistry
@@ -154,6 +155,7 @@ def model(
154155
variables: t.Optional[t.Dict[str, t.Any]] = None,
155156
infer_names: t.Optional[bool] = False,
156157
blueprint_variables: t.Optional[t.Dict[str, t.Any]] = None,
158+
virtual_environment_mode: VirtualEnvironmentMode = VirtualEnvironmentMode.default,
157159
) -> Model:
158160
"""Get the model registered by this function."""
159161
env: t.Dict[str, t.Tuple[t.Any, t.Optional[bool]]] = {}
@@ -228,6 +230,7 @@ def model(
228230
"audit_definitions": audit_definitions,
229231
"signal_definitions": signal_definitions,
230232
"blueprint_variables": blueprint_variables,
233+
"virtual_environment_mode": virtual_environment_mode,
231234
**rendered_fields,
232235
}
233236

sqlmesh/core/model/definition.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1062,6 +1062,7 @@ def _data_hash_values(self) -> t.List[str]:
10621062
self.gateway,
10631063
self.interval_unit.value if self.interval_unit is not None else None,
10641064
str(self.optimize_query) if self.optimize_query is not None else None,
1065+
self.virtual_environment_mode.value,
10651066
]
10661067

10671068
for column_name, column_type in (self.columns_to_types_ or {}).items():
@@ -2954,6 +2955,7 @@ def render_expression(
29542955
)
29552956
),
29562957
"formatting": str,
2958+
"virtual_environment_mode": lambda value: exp.Literal.string(value.value),
29572959
}
29582960

29592961

sqlmesh/core/model/meta.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from sqlglot.optimizer.normalize_identifiers import normalize_identifiers
1111

1212
from sqlmesh.core import dialect as d
13+
from sqlmesh.core.config.common import VirtualEnvironmentMode
1314
from sqlmesh.core.config.linter import LinterConfig
1415
from sqlmesh.core.dialect import normalize_model_name, extract_func_call
1516
from sqlmesh.core.model.common import (
@@ -83,6 +84,7 @@ class ModelMeta(_Node):
8384
default=None, exclude=True, alias="ignored_rules"
8485
)
8586
formatting: t.Optional[bool] = Field(default=None, exclude=True)
87+
virtual_environment_mode: VirtualEnvironmentMode = VirtualEnvironmentMode.default
8688

8789
_bool_validator = bool_validator
8890
_model_kind_validator = model_kind_validator

sqlmesh/core/plan/builder.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -601,7 +601,7 @@ def _categorize_snapshots(
601601
# If the model kind changes mark as breaking
602602
if snapshot.is_model and snapshot.name in self._context_diff.modified_snapshots:
603603
_, old = self._context_diff.modified_snapshots[snapshot.name]
604-
if _is_breaking_kind_change(old, snapshot):
604+
if _should_force_breaking_change(old, snapshot):
605605
category = SnapshotChangeCategory.BREAKING
606606

607607
snapshot.categorize_as(category)
@@ -766,7 +766,7 @@ def _is_forward_only_change(self, s_id: SnapshotId) -> bool:
766766
if snapshot.name in self._context_diff.modified_snapshots:
767767
_, old = self._context_diff.modified_snapshots[snapshot.name]
768768
# If the model kind has changed in a breaking way, then we can't consider this to be a forward-only change.
769-
if snapshot.is_model and _is_breaking_kind_change(old, snapshot):
769+
if snapshot.is_model and _should_force_breaking_change(old, snapshot):
770770
return False
771771
return (
772772
snapshot.is_model
@@ -884,7 +884,10 @@ def _modified_and_added_snapshots(self) -> t.List[Snapshot]:
884884
]
885885

886886

887-
def _is_breaking_kind_change(old: Snapshot, new: Snapshot) -> bool:
887+
def _should_force_breaking_change(old: Snapshot, new: Snapshot) -> bool:
888+
if old.virtual_environment_mode != new.virtual_environment_mode:
889+
# If the virtual environment mode has changed, then it's a breaking change
890+
return True
888891
if old.model.kind.name == new.model.kind.name:
889892
# If the kind hasn't changed, then it's not a breaking change
890893
return False

sqlmesh/core/snapshot/definition.py

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,6 @@ class SnapshotInfoMixin(ModelKindMixin):
337337
base_table_name_override: t.Optional[str]
338338
dev_table_suffix: str
339339
table_naming_convention: TableNamingConvention
340-
virtual_environment_mode: VirtualEnvironmentMode
341340

342341
@cached_property
343342
def identifier(self) -> str:
@@ -383,6 +382,10 @@ def is_new_version(self) -> bool:
383382
def fully_qualified_table(self) -> t.Optional[exp.Table]:
384383
raise NotImplementedError
385384

385+
@property
386+
def virtual_environment_mode(self) -> VirtualEnvironmentMode:
387+
raise NotImplementedError
388+
386389
@property
387390
def is_forward_only(self) -> bool:
388391
return self.change_category == SnapshotChangeCategory.FORWARD_ONLY
@@ -494,8 +497,10 @@ class SnapshotTableInfo(PydanticModel, SnapshotInfoMixin, frozen=True):
494497
custom_materialization: t.Optional[str] = None
495498
dev_table_suffix: str
496499
model_gateway: t.Optional[str] = None
497-
table_naming_convention: TableNamingConvention = Field(default=TableNamingConvention.default)
498-
virtual_environment_mode: VirtualEnvironmentMode = Field(default=VirtualEnvironmentMode.default)
500+
table_naming_convention: TableNamingConvention = TableNamingConvention.default
501+
virtual_environment_mode_: VirtualEnvironmentMode = Field(
502+
default=VirtualEnvironmentMode.default, alias="virtual_environment_mode"
503+
)
499504

500505
def __lt__(self, other: SnapshotTableInfo) -> bool:
501506
return self.name < other.name
@@ -527,6 +532,10 @@ def table_info(self) -> SnapshotTableInfo:
527532
"""Helper method to return self."""
528533
return self
529534

535+
@property
536+
def virtual_environment_mode(self) -> VirtualEnvironmentMode:
537+
return self.virtual_environment_mode_
538+
530539
@property
531540
def data_version(self) -> SnapshotDataVersion:
532541
return SnapshotDataVersion(
@@ -624,7 +633,6 @@ class Snapshot(PydanticModel, SnapshotInfoMixin):
624633
table_naming_convention_: TableNamingConvention = Field(
625634
default=TableNamingConvention.default, alias="table_naming_convention"
626635
)
627-
virtual_environment_mode: VirtualEnvironmentMode = Field(default=VirtualEnvironmentMode.default)
628636

629637
@field_validator("ttl")
630638
@classmethod
@@ -677,7 +685,6 @@ def from_node(
677685
version: t.Optional[str] = None,
678686
cache: t.Optional[t.Dict[str, SnapshotFingerprint]] = None,
679687
table_naming_convention: TableNamingConvention = TableNamingConvention.default,
680-
virtual_environment_mode: VirtualEnvironmentMode = VirtualEnvironmentMode.default,
681688
) -> Snapshot:
682689
"""Creates a new snapshot for a node.
683690
@@ -689,7 +696,6 @@ def from_node(
689696
version: The version that a snapshot is associated with. Usually set during the planning phase.
690697
cache: Cache of node name to fingerprints.
691698
table_naming_convention: Convention to follow when generating the physical table name
692-
virtual_environment_mode: Mode for handling virtual environments
693699
694700
Returns:
695701
The newly created snapshot.
@@ -722,7 +728,6 @@ def from_node(
722728
ttl=ttl,
723729
version=version,
724730
table_naming_convention=table_naming_convention,
725-
virtual_environment_mode=virtual_environment_mode,
726731
)
727732

728733
def __eq__(self, other: t.Any) -> bool:
@@ -1384,6 +1389,12 @@ def custom_materialization(self) -> t.Optional[str]:
13841389
return t.cast(CustomKind, self.model.kind).materialization
13851390
return None
13861391

1392+
@property
1393+
def virtual_environment_mode(self) -> VirtualEnvironmentMode:
1394+
return (
1395+
self.model.virtual_environment_mode if self.is_model else VirtualEnvironmentMode.default
1396+
)
1397+
13871398
def _ensure_categorized(self) -> None:
13881399
if not self.change_category:
13891400
raise SQLMeshError(f"Snapshot {self.snapshot_id} has not been categorized yet.")

tests/core/test_model.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1907,7 +1907,8 @@ def test_render_definition_with_defaults():
19071907
dialect spark,
19081908
kind VIEW (
19091909
materialized FALSE
1910-
)
1910+
),
1911+
virtual_environment_mode 'full'
19111912
);
19121913
19131914
{query}
@@ -5730,7 +5731,7 @@ def test_default_catalog_sql(assert_exp_eq):
57305731
The system is not designed to actually support having an engine that doesn't support default catalog
57315732
to start supporting it or the reverse of that. If that did happen then bugs would occur.
57325733
"""
5733-
HASH_WITH_CATALOG = "516937963"
5734+
HASH_WITH_CATALOG = "1269513823"
57345735

57355736
# Test setting default catalog doesn't change hash if it matches existing logic
57365737
expressions = d.parse(
@@ -5896,7 +5897,7 @@ def test_default_catalog_sql(assert_exp_eq):
58965897

58975898

58985899
def test_default_catalog_python():
5899-
HASH_WITH_CATALOG = "770057346"
5900+
HASH_WITH_CATALOG = "2728996410"
59005901

59015902
@model(name="db.table", kind="full", columns={'"COL"': "int"})
59025903
def my_model(context, **kwargs):
@@ -5988,7 +5989,7 @@ def test_default_catalog_external_model():
59885989
Since external models fqns are the only thing affected by default catalog, and when they change new snapshots
59895990
are made, the hash will be the same across different names.
59905991
"""
5991-
EXPECTED_HASH = "3614876346"
5992+
EXPECTED_HASH = "763256265"
59925993

59935994
model = create_external_model("db.table", columns={"a": "int", "limit": "int"})
59945995
assert model.default_catalog is None

tests/core/test_plan_stages.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1399,19 +1399,19 @@ def test_build_plan_stages_virtual_environment_mode_filtering(
13991399
name="full_model",
14001400
query=parse_one("select 1, ds"),
14011401
kind=dict(name=ModelKindName.INCREMENTAL_BY_TIME_RANGE, time_column="ds"),
1402+
virtual_environment_mode=VirtualEnvironmentMode.FULL,
14021403
)
14031404
)
1404-
snapshot_full.virtual_environment_mode = VirtualEnvironmentMode.FULL
14051405
snapshot_full.categorize_as(SnapshotChangeCategory.BREAKING)
14061406

14071407
snapshot_dev_only = make_snapshot(
14081408
SqlModel(
14091409
name="dev_only_model",
14101410
query=parse_one("select 2, ds"),
14111411
kind=dict(name=ModelKindName.INCREMENTAL_BY_TIME_RANGE, time_column="ds"),
1412+
virtual_environment_mode=VirtualEnvironmentMode.DEV_ONLY,
14121413
)
14131414
)
1414-
snapshot_dev_only.virtual_environment_mode = VirtualEnvironmentMode.DEV_ONLY
14151415
snapshot_dev_only.categorize_as(SnapshotChangeCategory.BREAKING)
14161416

14171417
# Mock state reader
@@ -1593,9 +1593,9 @@ def test_build_plan_stages_virtual_environment_mode_no_updates(
15931593
name="dev_only_model",
15941594
query=parse_one("select 1, ds"),
15951595
kind=dict(name=ModelKindName.INCREMENTAL_BY_TIME_RANGE, time_column="ds"),
1596+
virtual_environment_mode=VirtualEnvironmentMode.DEV_ONLY,
15961597
)
15971598
)
1598-
snapshot_dev_only.virtual_environment_mode = VirtualEnvironmentMode.DEV_ONLY
15991599
snapshot_dev_only.categorize_as(SnapshotChangeCategory.BREAKING)
16001600

16011601
# Mock state reader

0 commit comments

Comments
 (0)