Skip to content

Commit 0872bac

Browse files
authored
Fix: Support of vars in on-run-start / on-run-end hooks in dbt projects (#4554)
1 parent b04d10a commit 0872bac

File tree

5 files changed

+63
-20
lines changed

5 files changed

+63
-20
lines changed

sqlmesh/core/environment.py

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,39 @@ class EnvironmentStatements(PydanticModel):
250250
python_env: t.Dict[str, Executable]
251251
jinja_macros: t.Optional[JinjaMacroRegistry] = None
252252

253+
def render_before_all(
254+
self,
255+
dialect: str,
256+
default_catalog: t.Optional[str] = None,
257+
**render_kwargs: t.Any,
258+
) -> t.List[str]:
259+
return self.render(RuntimeStage.BEFORE_ALL, dialect, default_catalog, **render_kwargs)
260+
261+
def render_after_all(
262+
self,
263+
dialect: str,
264+
default_catalog: t.Optional[str] = None,
265+
**render_kwargs: t.Any,
266+
) -> t.List[str]:
267+
return self.render(RuntimeStage.AFTER_ALL, dialect, default_catalog, **render_kwargs)
268+
269+
def render(
270+
self,
271+
runtime_stage: RuntimeStage,
272+
dialect: str,
273+
default_catalog: t.Optional[str] = None,
274+
**render_kwargs: t.Any,
275+
) -> t.List[str]:
276+
return render_statements(
277+
statements=getattr(self, runtime_stage.value),
278+
dialect=dialect,
279+
default_catalog=default_catalog,
280+
python_env=self.python_env,
281+
jinja_macros=self.jinja_macros,
282+
runtime_stage=runtime_stage,
283+
**render_kwargs,
284+
)
285+
253286

254287
def execute_environment_statements(
255288
adapter: EngineAdapter,
@@ -266,18 +299,15 @@ def execute_environment_statements(
266299
rendered_expressions = [
267300
expr
268301
for statements in environment_statements
269-
for expr in render_statements(
270-
statements=getattr(statements, runtime_stage.value),
302+
for expr in statements.render(
303+
runtime_stage=runtime_stage,
271304
dialect=adapter.dialect,
272305
default_catalog=default_catalog,
273-
python_env=statements.python_env,
274-
jinja_macros=statements.jinja_macros,
275306
snapshots=snapshots,
276307
start=start,
277308
end=end,
278309
execution_time=execution_time,
279310
environment_naming_info=environment_naming_info,
280-
runtime_stage=runtime_stage,
281311
engine_adapter=adapter,
282312
)
283313
]

sqlmesh/dbt/loader.py

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import sys
55
import typing as t
66
import sqlmesh.core.dialect as d
7-
from sqlglot.optimizer.simplify import gen
87
from pathlib import Path
98
from sqlmesh.core import constants as c
109
from sqlmesh.core.config import (
@@ -17,9 +16,9 @@
1716
from sqlmesh.core.loader import CacheBase, LoadedProject, Loader
1817
from sqlmesh.core.macros import MacroRegistry, macro
1918
from sqlmesh.core.model import Model, ModelCache
20-
from sqlmesh.core.model.common import make_python_env
2119
from sqlmesh.core.signal import signal
2220
from sqlmesh.dbt.basemodel import BMC, BaseModelConfig
21+
from sqlmesh.dbt.common import Dependencies
2322
from sqlmesh.dbt.context import DbtContext
2423
from sqlmesh.dbt.model import ModelConfig
2524
from sqlmesh.dbt.profile import Profile
@@ -259,22 +258,18 @@ def _load_environment_statements(self, macros: MacroRegistry) -> t.List[Environm
259258

260259
if statements := on_run_start + on_run_end:
261260
jinja_references, used_variables = extract_macro_references_and_variables(
262-
*(gen(stmt) for stmt in statements)
261+
*statements
263262
)
264263

265-
jinja_registry = make_jinja_registry(
266-
context.jinja_macros, package_name, jinja_references
264+
statements_context = context.context_for_dependencies(
265+
Dependencies(
266+
variables=used_variables,
267+
)
267268
)
268-
269-
python_env = make_python_env(
270-
[s for stmt in statements for s in d.parse(stmt, default_dialect=dialect)],
271-
jinja_macro_references=jinja_references,
272-
module_path=self.config_path,
273-
macros=macros,
274-
variables=context.variables,
275-
used_variables=used_variables,
276-
path=self.config_path,
269+
jinja_registry = make_jinja_registry(
270+
statements_context.jinja_macros, package_name, jinja_references
277271
)
272+
jinja_registry.add_globals(statements_context.jinja_globals)
278273

279274
hooks_by_package_name[package_name] = EnvironmentStatements(
280275
before_all=[
@@ -285,7 +280,7 @@ def _load_environment_statements(self, macros: MacroRegistry) -> t.List[Environm
285280
d.jinja_statement(stmt).sql(dialect=dialect)
286281
for stmt in on_run_end or []
287282
],
288-
python_env=python_env,
283+
python_env={},
289284
jinja_macros=jinja_registry,
290285
)
291286
# Project hooks should be executed first and then rest of the packages

tests/core/test_integration.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4345,6 +4345,21 @@ def test_dbt_dialect_with_normalization_strategy(init_and_plan_context: t.Callab
43454345
assert context.default_dialect == "duckdb,normalization_strategy=LOWERCASE"
43464346

43474347

4348+
@time_machine.travel("2023-01-08 15:00:00 UTC")
4349+
def test_dbt_before_all_with_var(init_and_plan_context: t.Callable):
4350+
_, plan = init_and_plan_context(
4351+
"tests/fixtures/dbt/sushi_test", config="test_config_with_normalization_strategy"
4352+
)
4353+
environment_statements = plan.to_evaluatable().environment_statements
4354+
assert environment_statements
4355+
rendered_statements = [e.render_before_all(dialect="duckdb") for e in environment_statements]
4356+
assert rendered_statements[0] == [
4357+
"CREATE TABLE IF NOT EXISTS analytic_stats (physical_table TEXT, evaluation_time TEXT)",
4358+
"CREATE TABLE IF NOT EXISTS to_be_executed_last (col TEXT)",
4359+
'SELECT 1 AS "1"',
4360+
]
4361+
4362+
43484363
@pytest.mark.parametrize(
43494364
"context_fixture",
43504365
["sushi_context", "sushi_dbt_context", "sushi_test_dbt_context", "sushi_no_default_catalog"],

tests/dbt/test_adapter.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,7 @@ def test_on_run_start_end(copy_to_temp_path):
288288
assert root_environment_statements.before_all == [
289289
"JINJA_STATEMENT_BEGIN;\nCREATE TABLE IF NOT EXISTS analytic_stats (physical_table VARCHAR, evaluation_time VARCHAR);\nJINJA_END;",
290290
"JINJA_STATEMENT_BEGIN;\nCREATE TABLE IF NOT EXISTS to_be_executed_last (col VARCHAR);\nJINJA_END;",
291+
'JINJA_STATEMENT_BEGIN;\nSELECT {{ var("yet_another_var") }}\nJINJA_END;',
291292
]
292293
assert root_environment_statements.after_all == [
293294
"JINJA_STATEMENT_BEGIN;\n{{ create_tables(schemas) }}\nJINJA_END;",
@@ -317,6 +318,7 @@ def test_on_run_start_end(copy_to_temp_path):
317318
assert rendered_before_all == [
318319
"CREATE TABLE IF NOT EXISTS analytic_stats (physical_table TEXT, evaluation_time TEXT)",
319320
"CREATE TABLE IF NOT EXISTS to_be_executed_last (col TEXT)",
321+
'SELECT 1 AS "1"',
320322
]
321323

322324
# The jinja macro should have resolved the schemas for this environment and generated corresponding statements

tests/fixtures/dbt/sushi_test/dbt_project.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ vars:
6262
on-run-start:
6363
- 'CREATE TABLE IF NOT EXISTS analytic_stats (physical_table VARCHAR, evaluation_time VARCHAR);'
6464
- 'CREATE TABLE IF NOT EXISTS to_be_executed_last (col VARCHAR);'
65+
- 'SELECT {{ var("yet_another_var") }}'
6566
on-run-end:
6667
- '{{ create_tables(schemas) }}'
6768
- 'DROP TABLE to_be_executed_last;'

0 commit comments

Comments
 (0)