Skip to content

Commit f8c910c

Browse files
committed
move to plan_builder, edit possible flags, update EvaluatablePlan
1 parent 32f906f commit f8c910c

4 files changed

Lines changed: 141 additions & 30 deletions

File tree

sqlmesh/core/context.py

Lines changed: 58 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1230,18 +1230,6 @@ def plan(
12301230
Returns:
12311231
The populated Plan object.
12321232
"""
1233-
1234-
flags = {
1235-
k: v for k, v in locals().items() if k not in {"self", "environment"} if v is not None
1236-
}
1237-
skip_tests = skip_tests or False
1238-
no_gaps = no_gaps or False
1239-
skip_backfill = skip_backfill or False
1240-
empty_backfill = empty_backfill or False
1241-
run = run or False
1242-
diff_rendered = diff_rendered or False
1243-
skip_linter = skip_linter or False
1244-
12451233
plan_builder = self.plan_builder(
12461234
environment,
12471235
start=start,
@@ -1265,7 +1253,6 @@ def plan(
12651253
run=run,
12661254
diff_rendered=diff_rendered,
12671255
skip_linter=skip_linter,
1268-
flags=flags,
12691256
)
12701257

12711258
if no_auto_categorization:
@@ -1291,11 +1278,11 @@ def plan_builder(
12911278
end: t.Optional[TimeLike] = None,
12921279
execution_time: t.Optional[TimeLike] = None,
12931280
create_from: t.Optional[str] = None,
1294-
skip_tests: bool = False,
1281+
skip_tests: t.Optional[bool] = None,
12951282
restate_models: t.Optional[t.Iterable[str]] = None,
1296-
no_gaps: bool = False,
1297-
skip_backfill: bool = False,
1298-
empty_backfill: bool = False,
1283+
no_gaps: t.Optional[bool] = None,
1284+
skip_backfill: t.Optional[bool] = None,
1285+
empty_backfill: t.Optional[bool] = None,
12991286
forward_only: t.Optional[bool] = None,
13001287
allow_destructive_models: t.Optional[t.Collection[str]] = None,
13011288
no_auto_categorization: t.Optional[bool] = None,
@@ -1305,10 +1292,9 @@ def plan_builder(
13051292
backfill_models: t.Optional[t.Collection[str]] = None,
13061293
categorizer_config: t.Optional[CategorizerConfig] = None,
13071294
enable_preview: t.Optional[bool] = None,
1308-
run: bool = False,
1309-
diff_rendered: bool = False,
1310-
skip_linter: bool = False,
1311-
flags: t.Optional[t.Dict[str, t.Any]] = None,
1295+
run: t.Optional[bool] = None,
1296+
diff_rendered: t.Optional[bool] = None,
1297+
skip_linter: t.Optional[bool] = None,
13121298
) -> PlanBuilder:
13131299
"""Creates a plan builder.
13141300
@@ -1349,6 +1335,56 @@ def plan_builder(
13491335
Returns:
13501336
The plan builder.
13511337
"""
1338+
kwargs: t.Dict[
1339+
str,
1340+
t.Union[
1341+
t.Optional[TimeLike],
1342+
t.Optional[str],
1343+
t.Optional[bool],
1344+
t.Optional[t.Iterable[str]],
1345+
t.Optional[t.Collection[str]],
1346+
],
1347+
] = {
1348+
"start": start,
1349+
"end": end,
1350+
"execution_time": execution_time,
1351+
"create_from": create_from,
1352+
"skip_tests": skip_tests,
1353+
"restate_models": restate_models,
1354+
"no_gaps": no_gaps,
1355+
"skip_backfill": skip_backfill,
1356+
"empty_backfill": empty_backfill,
1357+
"forward_only": forward_only,
1358+
"allow_destructive_models": allow_destructive_models,
1359+
"no_auto_categorization": no_auto_categorization,
1360+
"effective_from": effective_from,
1361+
"include_unmodified": include_unmodified,
1362+
"select_models": select_models,
1363+
"backfill_models": backfill_models,
1364+
"enable_preview": enable_preview,
1365+
"run": run,
1366+
"diff_rendered": diff_rendered,
1367+
"skip_linter": skip_linter,
1368+
}
1369+
user_defined_flags: t.Dict[
1370+
str,
1371+
t.Union[
1372+
t.Optional[TimeLike],
1373+
t.Optional[str],
1374+
t.Optional[bool],
1375+
t.Optional[t.Iterable[str]],
1376+
t.Optional[t.Collection[str]],
1377+
],
1378+
] = {k: v for k, v in kwargs.items() if v is not None}
1379+
1380+
skip_tests = skip_tests or False
1381+
no_gaps = no_gaps or False
1382+
skip_backfill = skip_backfill or False
1383+
empty_backfill = empty_backfill or False
1384+
run = run or False
1385+
diff_rendered = diff_rendered or False
1386+
skip_linter = skip_linter or False
1387+
13521388
environment = environment or self.config.default_target_environment
13531389
environment = Environment.sanitize_name(environment)
13541390
is_dev = environment != c.PROD
@@ -1483,7 +1519,7 @@ def plan_builder(
14831519
engine_schema_differ=self.engine_adapter.SCHEMA_DIFFER,
14841520
interval_end_per_model=max_interval_end_per_model,
14851521
console=self.console,
1486-
flags=flags,
1522+
user_defined_flags=user_defined_flags,
14871523
)
14881524

14891525
def apply(

sqlmesh/core/plan/builder.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,18 @@ def __init__(
107107
ensure_finalized_snapshots: bool = False,
108108
interval_end_per_model: t.Optional[t.Dict[str, int]] = None,
109109
console: t.Optional[PlanBuilderConsole] = None,
110-
flags: t.Optional[t.Dict[str, t.Any]] = None,
110+
user_defined_flags: t.Optional[
111+
t.Dict[
112+
str,
113+
t.Union[
114+
t.Optional[TimeLike],
115+
t.Optional[str],
116+
t.Optional[bool],
117+
t.Optional[t.Iterable[str]],
118+
t.Optional[t.Collection[str]],
119+
],
120+
]
121+
] = None,
111122
):
112123
self._context_diff = context_diff
113124
self._no_gaps = no_gaps
@@ -135,7 +146,7 @@ def __init__(
135146
self._engine_schema_differ = engine_schema_differ
136147
self._console = console or get_console()
137148
self._choices: t.Dict[SnapshotId, SnapshotChangeCategory] = {}
138-
self._flags = flags
149+
self._user_defined_flags = user_defined_flags
139150

140151
self._start = start
141152
if not self._start and (
@@ -282,7 +293,7 @@ def build(self) -> Plan:
282293
execution_time=self._execution_time,
283294
end_bounded=self._end_bounded,
284295
ensure_finalized_snapshots=self._ensure_finalized_snapshots,
285-
flags=self._flags,
296+
user_defined_flags=self._user_defined_flags,
286297
)
287298
self._latest_plan = plan
288299
return plan

sqlmesh/core/plan/definition.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,18 @@ class Plan(PydanticModel, frozen=True):
6363
effective_from: t.Optional[TimeLike] = None
6464
execution_time: t.Optional[TimeLike] = None
6565

66-
flags: t.Optional[t.Dict[str, t.Any]] = None
66+
user_defined_flags: t.Optional[
67+
t.Dict[
68+
str,
69+
t.Union[
70+
t.Optional[TimeLike],
71+
t.Optional[str],
72+
t.Optional[bool],
73+
t.Optional[t.Iterable[str]],
74+
t.Optional[t.Collection[str]],
75+
],
76+
]
77+
] = None
6778

6879
@cached_property
6980
def start(self) -> TimeLike:
@@ -264,6 +275,7 @@ def to_evaluatable(self) -> EvaluatablePlan:
264275
if s.is_model and s.model.disable_restatement
265276
},
266277
environment_statements=self.context_diff.environment_statements,
278+
user_defined_flags=self.user_defined_flags,
267279
)
268280

269281
@cached_property
@@ -296,6 +308,18 @@ class EvaluatablePlan(PydanticModel):
296308
execution_time: t.Optional[TimeLike] = None
297309
disabled_restatement_models: t.Set[str]
298310
environment_statements: t.Optional[t.List[EnvironmentStatements]] = None
311+
user_defined_flags: t.Optional[
312+
t.Dict[
313+
str,
314+
t.Union[
315+
t.Optional[TimeLike],
316+
t.Optional[str],
317+
t.Optional[bool],
318+
t.Optional[t.Iterable[str]],
319+
t.Optional[t.Collection[str]],
320+
],
321+
]
322+
] = None
299323

300324
def is_selected_for_backfill(self, model_fqn: str) -> bool:
301325
return self.models_to_backfill is None or model_fqn in self.models_to_backfill

tests/core/test_plan.py

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3107,8 +3107,48 @@ def test_set_choice_for_forward_only_model(make_snapshot):
31073107
)
31083108

31093109

3110-
def test_flags(sushi_context: Context):
3111-
plan = sushi_context.plan(no_prompts=True, run=True, execution_time="2025-01-01")
3112-
sushi_context.apply(plan)
3110+
def test_user_defined_flags(sushi_context: Context):
3111+
expected_flags = {
3112+
"run": True,
3113+
"execution_time": "2025-01-01",
3114+
}
3115+
plan_a = sushi_context.plan(no_prompts=True, run=True, execution_time="2025-01-01")
3116+
assert plan_a.user_defined_flags == expected_flags
3117+
evaluatable_plan = plan_a.to_evaluatable()
3118+
assert evaluatable_plan.user_defined_flags == expected_flags
31133119

3114-
assert plan.flags == {"no_prompts": True, "run": True, "execution_time": "2025-01-01"}
3120+
plan_b = sushi_context.plan()
3121+
assert plan_b.user_defined_flags == {}
3122+
evaluatable_plan_b = plan_b.to_evaluatable()
3123+
assert evaluatable_plan_b.user_defined_flags == {}
3124+
3125+
context_diff = ContextDiff(
3126+
environment="test_environment",
3127+
is_new_environment=True,
3128+
is_unfinalized_environment=False,
3129+
normalize_environment_name=True,
3130+
create_from="prod",
3131+
create_from_env_exists=True,
3132+
added=set(),
3133+
removed_snapshots={},
3134+
modified_snapshots={},
3135+
snapshots={},
3136+
new_snapshots={},
3137+
previous_plan_id=None,
3138+
previously_promoted_snapshot_ids=set(),
3139+
previous_finalized_snapshots=None,
3140+
previous_gateway_managed_virtual_layer=False,
3141+
gateway_managed_virtual_layer=False,
3142+
)
3143+
plan_builder = PlanBuilder(
3144+
context_diff,
3145+
DuckDBEngineAdapter.SCHEMA_DIFFER,
3146+
forward_only=True,
3147+
user_defined_flags={"forward_only": True},
3148+
).build()
3149+
assert plan_builder.user_defined_flags == {"forward_only": True}
3150+
plan_builder = PlanBuilder(
3151+
context_diff,
3152+
DuckDBEngineAdapter.SCHEMA_DIFFER,
3153+
).build()
3154+
assert plan_builder.user_defined_flags == None

0 commit comments

Comments
 (0)