Skip to content

Commit ba111a2

Browse files
committed
PR feedback
1 parent 837d730 commit ba111a2

File tree

7 files changed

+46
-124
lines changed

7 files changed

+46
-124
lines changed

sqlmesh/core/context.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1656,7 +1656,7 @@ def plan_builder(
16561656

16571657
# When handling prod restatements, only clear intervals from other model versions if we are using full virtual environments
16581658
# If we are not, then there is no point, because none of the data in dev environments can be promoted by definition
1659-
clear_restated_intervals_across_model_versions = (
1659+
restate_all_snapshots = (
16601660
expanded_restate_models is not None
16611661
and not is_dev
16621662
and self.config.virtual_environment_mode.is_full
@@ -1669,7 +1669,7 @@ def plan_builder(
16691669
execution_time=execution_time,
16701670
apply=self.apply,
16711671
restate_models=expanded_restate_models,
1672-
clear_restated_intervals_across_model_versions=clear_restated_intervals_across_model_versions,
1672+
restate_all_snapshots=restate_all_snapshots,
16731673
backfill_models=backfill_models,
16741674
no_gaps=no_gaps,
16751675
skip_backfill=skip_backfill,
@@ -1703,7 +1703,6 @@ def plan_builder(
17031703
},
17041704
explain=explain or False,
17051705
ignore_cron=ignore_cron or False,
1706-
always_include_local_changes=always_include_local_changes,
17071706
)
17081707

17091708
def apply(

sqlmesh/core/plan/builder.py

Lines changed: 4 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,9 @@ class PlanBuilder:
6565
restate_models: A list of models for which the data should be restated for the time range
6666
specified in this plan. Note: models defined outside SQLMesh (external) won't be a part
6767
of the restatement.
68-
clear_restated_intervals_across_model_versions: If restatements are present, this flag indicates whether or not the intervals
68+
restate_all_snapshots: If restatements are present, this flag indicates whether or not the intervals
6969
being restated should be cleared from state for other versions of this model (typically, versions that are present in other environments).
7070
If set to None, the default behaviour is to not clear anything unless the target environment is prod.
71-
always_include_local_changes: Usually when restatements are present, local changes in the filesystem are ignored.
72-
However, it can be desirable to deploy changes + restatements in the same plan, so this flag overrides the default behaviour.
7371
backfill_models: A list of fully qualified model names for which the data should be backfilled as part of this plan.
7472
no_gaps: Whether to ensure that new snapshots for nodes that are already a
7573
part of the target environment have no data gaps when compared against previous
@@ -108,8 +106,7 @@ def __init__(
108106
execution_time: t.Optional[TimeLike] = None,
109107
apply: t.Optional[t.Callable[[Plan], None]] = None,
110108
restate_models: t.Optional[t.Iterable[str]] = None,
111-
clear_restated_intervals_across_model_versions: bool = False,
112-
always_include_local_changes: t.Optional[bool] = None,
109+
restate_all_snapshots: bool = False,
113110
backfill_models: t.Optional[t.Iterable[str]] = None,
114111
no_gaps: bool = False,
115112
skip_backfill: bool = False,
@@ -161,9 +158,7 @@ def __init__(
161158
self._auto_categorization_enabled = auto_categorization_enabled
162159
self._include_unmodified = include_unmodified
163160
self._restate_models = set(restate_models) if restate_models is not None else None
164-
self._clear_restated_intervals_across_model_versions = (
165-
clear_restated_intervals_across_model_versions
166-
)
161+
self._restate_all_snapshots = restate_all_snapshots
167162
self._effective_from = effective_from
168163

169164
# note: this deliberately doesnt default to now() here.
@@ -182,7 +177,6 @@ def __init__(
182177
self._user_provided_flags = user_provided_flags
183178
self._selected_models = selected_models
184179
self._explain = explain
185-
self._always_include_local_changes = always_include_local_changes
186180

187181
self._start = start
188182
if not self._start and (
@@ -288,7 +282,6 @@ def build(self) -> Plan:
288282
if self._latest_plan:
289283
return self._latest_plan
290284

291-
self._ensure_no_new_snapshots_with_restatements()
292285
self._ensure_new_env_with_changes()
293286
self._ensure_valid_date_range()
294287
self._ensure_no_broken_references()
@@ -351,7 +344,7 @@ def build(self) -> Plan:
351344
deployability_index=deployability_index,
352345
selected_models_to_restate=self._restate_models,
353346
restatements=restatements,
354-
clear_restated_intervals_across_model_versions=self._clear_restated_intervals_across_model_versions,
347+
restate_all_snapshots=self._restate_all_snapshots,
355348
start_override_per_model=self._start_override_per_model,
356349
end_override_per_model=end_override_per_model,
357350
selected_models_to_backfill=self._backfill_models,
@@ -871,21 +864,6 @@ def _ensure_no_broken_references(self) -> None:
871864
f"""Removed {broken_references_msg} are referenced in '{snapshot.name}'. Please remove broken references before proceeding."""
872865
)
873866

874-
def _ensure_no_new_snapshots_with_restatements(self) -> None:
875-
if self._always_include_local_changes:
876-
# the sqlmesh_dbt cli sets "always include local changes" to deliberately allow changes and restatements
877-
# to be deployed in the same plan. If this is set, "force_no_diff" is also turned off on the ContextDiff
878-
# so that the user is shown the local changes that will be applied and must accept them in order to run the plan
879-
return
880-
881-
if self._restate_models is not None and (
882-
self._context_diff.new_snapshots or self._context_diff.modified_snapshots
883-
):
884-
raise PlanError(
885-
"Model changes and restatements can't be a part of the same plan. "
886-
"Revert or apply changes before proceeding with restatements."
887-
)
888-
889867
def _ensure_new_env_with_changes(self) -> None:
890868
if (
891869
self._is_dev

sqlmesh/core/plan/definition.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ class Plan(PydanticModel, frozen=True):
6666
6767
Note that dev previews are also considered restatements, so :selected_models_to_restate can be empty
6868
while :restatements is still populated with dev previews
69-
"""
70-
clear_restated_intervals_across_model_versions: bool
69+
"""
70+
restate_all_snapshots: bool
7171
"""Whether or not to clear intervals from state for other versions of the models listed in :restatements"""
7272

7373
start_override_per_model: t.Optional[t.Dict[str, datetime]]
@@ -270,7 +270,7 @@ def to_evaluatable(self) -> EvaluatablePlan:
270270
skip_backfill=self.skip_backfill,
271271
empty_backfill=self.empty_backfill,
272272
restatements={s.name: i for s, i in self.restatements.items()},
273-
clear_restated_intervals_across_model_versions=self.clear_restated_intervals_across_model_versions,
273+
restate_all_snapshots=self.restate_all_snapshots,
274274
is_dev=self.is_dev,
275275
allow_destructive_models=self.allow_destructive_models,
276276
allow_additive_models=self.allow_additive_models,
@@ -315,7 +315,7 @@ class EvaluatablePlan(PydanticModel):
315315
skip_backfill: bool
316316
empty_backfill: bool
317317
restatements: t.Dict[str, Interval]
318-
clear_restated_intervals_across_model_versions: bool
318+
restate_all_snapshots: bool
319319
is_dev: bool
320320
allow_destructive_models: t.Set[str]
321321
allow_additive_models: t.Set[str]

sqlmesh/core/plan/stages.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
SnapshotTableInfo,
1414
SnapshotId,
1515
)
16+
from sqlmesh.utils.errors import PlanError
1617

1718

1819
@dataclass
@@ -452,10 +453,16 @@ def _get_after_all_stage(
452453
def _get_restatement_stage(
453454
self, plan: EvaluatablePlan, snapshots_by_name: t.Dict[str, Snapshot]
454455
) -> t.Optional[RestatementStage]:
455-
if plan.restatements and plan.clear_restated_intervals_across_model_versions:
456-
return RestatementStage(
457-
all_snapshots=snapshots_by_name,
458-
)
456+
if plan.restate_all_snapshots:
457+
if plan.is_dev:
458+
raise PlanError(
459+
"Clearing intervals from state across dev model versions is only valid for prod plans"
460+
)
461+
462+
if plan.restatements:
463+
return RestatementStage(
464+
all_snapshots=snapshots_by_name,
465+
)
459466

460467
return None
461468

tests/core/test_plan.py

Lines changed: 1 addition & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -826,7 +826,7 @@ def test_missing_intervals_lookback(make_snapshot, mocker: MockerFixture):
826826
indirectly_modified={},
827827
deployability_index=DeployabilityIndex.all_deployable(),
828828
restatements={},
829-
clear_restated_intervals_across_model_versions=False,
829+
restate_all_snapshots=False,
830830
end_bounded=False,
831831
ensure_finalized_snapshots=False,
832832
start_override_per_model=None,
@@ -1075,68 +1075,6 @@ def test_restate_missing_model(make_snapshot, mocker: MockerFixture):
10751075
PlanBuilder(context_diff, restate_models=["missing"]).build()
10761076

10771077

1078-
def test_new_snapshots_with_restatements(make_snapshot, mocker: MockerFixture):
1079-
snapshot_a = make_snapshot(SqlModel(name="a", query=parse_one("select 1, ds")))
1080-
1081-
context_diff = ContextDiff(
1082-
environment="test_environment",
1083-
is_new_environment=True,
1084-
is_unfinalized_environment=False,
1085-
normalize_environment_name=True,
1086-
create_from="prod",
1087-
create_from_env_exists=True,
1088-
added=set(),
1089-
removed_snapshots={},
1090-
modified_snapshots={},
1091-
snapshots={snapshot_a.snapshot_id: snapshot_a},
1092-
new_snapshots={snapshot_a.snapshot_id: snapshot_a},
1093-
previous_plan_id=None,
1094-
previously_promoted_snapshot_ids=set(),
1095-
previous_finalized_snapshots=None,
1096-
previous_gateway_managed_virtual_layer=False,
1097-
gateway_managed_virtual_layer=False,
1098-
environment_statements=[],
1099-
)
1100-
1101-
with pytest.raises(
1102-
PlanError,
1103-
match=r"Model changes and restatements can't be a part of the same plan.*",
1104-
):
1105-
PlanBuilder(context_diff, restate_models=["a"]).build()
1106-
1107-
1108-
def test_new_snapshots_with_restatements_allowed_if_flag_set(
1109-
make_snapshot: t.Callable[..., Snapshot],
1110-
):
1111-
snapshot_a = make_snapshot(SqlModel(name="a", query=parse_one("select 1, ds")))
1112-
1113-
context_diff = ContextDiff(
1114-
environment="test_environment",
1115-
is_new_environment=True,
1116-
is_unfinalized_environment=False,
1117-
normalize_environment_name=True,
1118-
create_from="prod",
1119-
create_from_env_exists=True,
1120-
added=set(),
1121-
removed_snapshots={},
1122-
modified_snapshots={},
1123-
snapshots={snapshot_a.snapshot_id: snapshot_a},
1124-
new_snapshots={snapshot_a.snapshot_id: snapshot_a},
1125-
previous_plan_id=None,
1126-
previously_promoted_snapshot_ids=set(),
1127-
previous_finalized_snapshots=None,
1128-
previous_gateway_managed_virtual_layer=False,
1129-
gateway_managed_virtual_layer=False,
1130-
environment_statements=[],
1131-
)
1132-
1133-
plan = PlanBuilder(
1134-
context_diff, restate_models=[snapshot_a.name], always_include_local_changes=True
1135-
).build()
1136-
assert plan.restatements
1137-
assert plan.new_snapshots
1138-
1139-
11401078
def test_end_validation(make_snapshot, mocker: MockerFixture):
11411079
snapshot_a = make_snapshot(
11421080
SqlModel(

0 commit comments

Comments
 (0)