Skip to content

Commit 11e2952

Browse files
authored
Merge branch 'main' into add_fabric_warehouse
2 parents 486eb05 + b256ba5 commit 11e2952

File tree

11 files changed

+75
-38
lines changed

11 files changed

+75
-38
lines changed

README.md

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,7 @@ python -m venv .venv
145145
source .venv/bin/activate
146146
pip install 'sqlmesh[lsp]' # install the sqlmesh package with extensions to work with VSCode
147147
source .venv/bin/activate # reactivate the venv to ensure you're using the right installation
148-
sqlmesh init duckdb # get started right away with a local duckdb instance
149-
sqlmesh plan # see the plan for the changes you're making
148+
sqlmesh init # follow the prompts to get started (choose DuckDB)
150149
```
151150

152151
</details>
@@ -163,13 +162,12 @@ python -m venv .venv
163162
.\.venv\Scripts\Activate.ps1
164163
pip install 'sqlmesh[lsp]' # install the sqlmesh package with extensions to work with VSCode
165164
.\.venv\Scripts\Activate.ps1 # reactivate the venv to ensure you're using the right installation
166-
sqlmesh init duckdb # get started right away with a local duckdb instance
167-
sqlmesh plan # see the plan for the changes you're making
165+
sqlmesh init # follow the prompts to get started (choose DuckDB)
168166
```
169167
</details>
170168

171169

172-
Follow the [quickstart guide](https://sqlmesh.readthedocs.io/en/stable/quickstart/cli/#1-create-the-sqlmesh-project) to learn how to use SQLMesh. You already have a head start!
170+
Follow the [quickstart guide](https://sqlmesh.readthedocs.io/en/stable/quickstart/cli/) to learn how to use SQLMesh. You already have a head start!
173171

174172
Follow the [crash course](https://sqlmesh.readthedocs.io/en/stable/examples/sqlmesh_cli_crash_course/) to learn the core movesets and use the easy to reference cheat sheet.
175173

docs/readme/architecture_diagram.png

-5.89 KB
Loading

examples/sushi/models/orders.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
"end_ts": "int",
3737
"event_date": "date",
3838
},
39+
signals=[("test_signal", {"arg": 1})],
3940
)
4041
def execute(
4142
context: ExecutionContext,

sqlmesh/core/engine_adapter/mssql.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -90,18 +90,18 @@ def columns(
9090

9191
sql = (
9292
exp.select(
93-
"column_name",
94-
"data_type",
95-
"character_maximum_length",
96-
"numeric_precision",
97-
"numeric_scale",
93+
"COLUMN_NAME",
94+
"DATA_TYPE",
95+
"CHARACTER_MAXIMUM_LENGTH",
96+
"NUMERIC_PRECISION",
97+
"NUMERIC_SCALE",
9898
)
99-
.from_("information_schema.columns")
100-
.where(f"table_name = '{table.name}'")
99+
.from_("INFORMATION_SCHEMA.COLUMNS")
100+
.where(f"TABLE_NAME = '{table.name}'")
101101
)
102102
database_name = table.db
103103
if database_name:
104-
sql = sql.where(f"table_schema = '{database_name}'")
104+
sql = sql.where(f"TABLE_SCHEMA = '{database_name}'")
105105

106106
columns_raw = self.fetchall(sql, quote_identifiers=True)
107107

@@ -145,12 +145,12 @@ def table_exists(self, table_name: TableName) -> bool:
145145

146146
sql = (
147147
exp.select("1")
148-
.from_("information_schema.tables")
149-
.where(f"table_name = '{table.alias_or_name}'")
148+
.from_("INFORMATION_SCHEMA.TABLES")
149+
.where(f"TABLE_NAME = '{table.alias_or_name}'")
150150
)
151151
database_name = table.db
152152
if database_name:
153-
sql = sql.where(f"table_schema = '{database_name}'")
153+
sql = sql.where(f"TABLE_SCHEMA = '{database_name}'")
154154

155155
result = self.fetchone(sql, quote_identifiers=True)
156156

sqlmesh/core/loader.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,7 @@ def _load_python_models(
672672
default_catalog=self.context.default_catalog,
673673
infer_names=self.config.model_naming.infer_names,
674674
audit_definitions=audits,
675+
signal_definitions=signals,
675676
default_catalog_per_gateway=self.context.default_catalog_per_gateway,
676677
):
677678
if model.enabled:

sqlmesh/core/model/decorator.py

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from sqlglot.dialects.dialect import DialectType
1010

1111
from sqlmesh.core.macros import MacroRegistry
12+
from sqlmesh.core.signal import SignalRegistry
1213
from sqlmesh.utils.jinja import JinjaMacroRegistry
1314
from sqlmesh.core import constants as c
1415
from sqlmesh.core.dialect import MacroFunc, parse_one
@@ -48,23 +49,24 @@ def __init__(self, name: t.Optional[str] = None, is_sql: bool = False, **kwargs:
4849
self.kwargs = kwargs
4950

5051
# Make sure that argument values are expressions in order to pass validation in ModelMeta.
51-
calls = self.kwargs.pop("audits", [])
52-
self.kwargs["audits"] = [
53-
(
54-
(call, {})
55-
if isinstance(call, str)
56-
else (
57-
call[0],
58-
{
59-
arg_key: exp.convert(
60-
tuple(arg_value) if isinstance(arg_value, list) else arg_value
61-
)
62-
for arg_key, arg_value in call[1].items()
63-
},
52+
for function_call_attribute in ("audits", "signals"):
53+
calls = self.kwargs.pop(function_call_attribute, [])
54+
self.kwargs[function_call_attribute] = [
55+
(
56+
(call, {})
57+
if isinstance(call, str)
58+
else (
59+
call[0],
60+
{
61+
arg_key: exp.convert(
62+
tuple(arg_value) if isinstance(arg_value, list) else arg_value
63+
)
64+
for arg_key, arg_value in call[1].items()
65+
},
66+
)
6467
)
65-
)
66-
for call in calls
67-
]
68+
for call in calls
69+
]
6870

6971
if "default_catalog" in kwargs:
7072
raise ConfigError("`default_catalog` cannot be set on a per-model basis.")
@@ -142,6 +144,7 @@ def model(
142144
defaults: t.Optional[t.Dict[str, t.Any]] = None,
143145
macros: t.Optional[MacroRegistry] = None,
144146
jinja_macros: t.Optional[JinjaMacroRegistry] = None,
147+
signal_definitions: t.Optional[SignalRegistry] = None,
145148
audit_definitions: t.Optional[t.Dict[str, ModelAudit]] = None,
146149
dialect: t.Optional[str] = None,
147150
time_column_format: str = c.DEFAULT_TIME_COLUMN_FORMAT,
@@ -223,6 +226,7 @@ def model(
223226
"macros": macros,
224227
"jinja_macros": jinja_macros,
225228
"audit_definitions": audit_definitions,
229+
"signal_definitions": signal_definitions,
226230
"blueprint_variables": blueprint_variables,
227231
**rendered_fields,
228232
}

sqlmesh/core/plan/stages.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,11 @@ def _get_physical_layer_update_stage(
431431
return PhysicalLayerUpdateStage(
432432
snapshots=self._get_snapshots_to_create(plan, snapshots),
433433
all_snapshots=snapshots,
434-
snapshots_with_missing_intervals={s.snapshot_id for s in snapshots_to_intervals},
434+
snapshots_with_missing_intervals={
435+
s.snapshot_id
436+
for s in snapshots_to_intervals
437+
if plan.is_selected_for_backfill(s.name)
438+
},
435439
deployability_index=deployability_index,
436440
)
437441

tests/core/engine_adapter/test_mssql.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ def test_columns(adapter: MSSQLEngineAdapter):
7979
}
8080

8181
adapter.cursor.execute.assert_called_once_with(
82-
"""SELECT [column_name], [data_type], [character_maximum_length], [numeric_precision], [numeric_scale] FROM [information_schema].[columns] WHERE [table_name] = 'table' AND [table_schema] = 'db';"""
82+
"""SELECT [COLUMN_NAME], [DATA_TYPE], [CHARACTER_MAXIMUM_LENGTH], [NUMERIC_PRECISION], [NUMERIC_SCALE] FROM [INFORMATION_SCHEMA].[COLUMNS] WHERE [TABLE_NAME] = 'table' AND [TABLE_SCHEMA] = 'db';"""
8383
)
8484

8585

@@ -149,8 +149,8 @@ def test_table_exists(make_mocked_engine_adapter: t.Callable):
149149
resp = adapter.table_exists("db.table")
150150
adapter.cursor.execute.assert_called_once_with(
151151
"""SELECT 1 """
152-
"""FROM [information_schema].[tables] """
153-
"""WHERE [table_name] = 'table' AND [table_schema] = 'db';"""
152+
"""FROM [INFORMATION_SCHEMA].[TABLES] """
153+
"""WHERE [TABLE_NAME] = 'table' AND [TABLE_SCHEMA] = 'db';"""
154154
)
155155
assert resp
156156
adapter.cursor.fetchone.return_value = None
@@ -506,7 +506,7 @@ def test_replace_query(make_mocked_engine_adapter: t.Callable):
506506
adapter.replace_query("test_table", parse_one("SELECT a FROM tbl"), {"a": "int"})
507507

508508
assert to_sql_calls(adapter) == [
509-
"""SELECT 1 FROM [information_schema].[tables] WHERE [table_name] = 'test_table';""",
509+
"""SELECT 1 FROM [INFORMATION_SCHEMA].[TABLES] WHERE [TABLE_NAME] = 'test_table';""",
510510
"TRUNCATE TABLE [test_table];",
511511
"INSERT INTO [test_table] ([a]) SELECT [a] FROM [tbl];",
512512
]

tests/core/test_context.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2122,7 +2122,7 @@ def test_check_intervals(sushi_context, mocker):
21222122
intervals = sushi_context.check_intervals(environment=None, no_signals=False, select_models=[])
21232123

21242124
min_intervals = 19
2125-
assert spy.call_count == 1
2125+
assert spy.call_count == 2
21262126
assert len(intervals) >= min_intervals
21272127

21282128
for i in intervals.values():

tests/core/test_model.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5303,6 +5303,30 @@ def my_signal(batch):
53035303
)
53045304

53055305

5306+
def test_load_python_model_with_signals():
5307+
@signal()
5308+
def always_true(batch):
5309+
return True
5310+
5311+
@model(
5312+
name="model_with_signal",
5313+
kind="full",
5314+
columns={'"COL"': "int"},
5315+
signals=[("always_true", {})],
5316+
)
5317+
def model_with_signal(context, **kwargs):
5318+
return pd.DataFrame([{"COL": 1}])
5319+
5320+
models = model.get_registry()["model_with_signal"].models(
5321+
get_variables=lambda _: {},
5322+
path=Path("."),
5323+
module_path=Path("."),
5324+
signal_definitions=signal.get_registry(),
5325+
)
5326+
assert len(models) == 1
5327+
assert models[0].signals == [("always_true", {})]
5328+
5329+
53065330
def test_null_column_type():
53075331
expressions = d.parse(
53085332
"""

tests/core/test_plan_stages.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,10 @@ def test_build_plan_stages_basic(
141141
snapshot_a.snapshot_id,
142142
snapshot_b.snapshot_id,
143143
}
144+
assert {s.snapshot_id for s in physical_stage.snapshots_with_missing_intervals} == {
145+
snapshot_a.snapshot_id,
146+
snapshot_b.snapshot_id,
147+
}
144148
assert physical_stage.deployability_index == DeployabilityIndex.all_deployable()
145149

146150
# Verify BackfillStage
@@ -357,6 +361,7 @@ def test_build_plan_stages_select_models(
357361
assert len(physical_stage.snapshots) == 1
358362
assert {s.snapshot_id for s in physical_stage.snapshots} == {snapshot_a.snapshot_id}
359363
assert physical_stage.deployability_index == DeployabilityIndex.all_deployable()
364+
assert physical_stage.snapshots_with_missing_intervals == {snapshot_a.snapshot_id}
360365

361366
# Verify BackfillStage
362367
backfill_stage = stages[2]

0 commit comments

Comments
 (0)