Skip to content

Commit 3460d3f

Browse files
authored
Merge branch 'main' into fix/sqlmesh-stale-cache-file-not-found
2 parents 35c490c + 3be5bba commit 3460d3f

25 files changed

Lines changed: 336 additions & 82 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ dependencies = [
2424
"requests",
2525
"rich[jupyter]",
2626
"ruamel.yaml",
27-
"sqlglot~=30.2.1",
27+
"sqlglot~=30.4.2",
2828
"tenacity",
2929
"time-machine",
3030
"json-stream"

sqlmesh/core/config/connection.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
ValidationInfo,
3535
field_validator,
3636
model_validator,
37+
validation_data,
3738
validation_error_message,
3839
get_concrete_types_from_typehint,
3940
)
@@ -1081,7 +1082,7 @@ def validate_execution_project(
10811082
v: t.Optional[str],
10821083
info: ValidationInfo,
10831084
) -> t.Optional[str]:
1084-
if v and not info.data.get("project"):
1085+
if v and not validation_data(info).get("project"):
10851086
raise ConfigError(
10861087
"If the `execution_project` field is specified, you must also specify the `project` field to provide a default object location."
10871088
)
@@ -1093,7 +1094,7 @@ def validate_quota_project(
10931094
v: t.Optional[str],
10941095
info: ValidationInfo,
10951096
) -> t.Optional[str]:
1096-
if v and not info.data.get("project"):
1097+
if v and not validation_data(info).get("project"):
10971098
raise ConfigError(
10981099
"If the `quota_project` field is specified, you must also specify the `project` field to provide a default object location."
10991100
)

sqlmesh/core/context.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1605,9 +1605,11 @@ def plan_builder(
16051605
backfill_models = None
16061606

16071607
models_override: t.Optional[UniqueKeyDict[str, Model]] = None
1608+
selected_fqns: t.Set[str] = set()
1609+
selected_deletion_fqns: t.Set[str] = set()
16081610
if select_models:
16091611
try:
1610-
models_override = model_selector.select_models(
1612+
models_override, selected_fqns = model_selector.select_models(
16111613
select_models,
16121614
environment,
16131615
fallback_env_name=create_from or c.PROD,
@@ -1622,12 +1624,17 @@ def plan_builder(
16221624
# Only backfill selected models unless explicitly specified.
16231625
backfill_models = model_selector.expand_model_selections(select_models)
16241626

1627+
if not backfill_models:
1628+
# The selection matched nothing locally. Check whether it matched models
1629+
# in the deployed environment that were deleted locally.
1630+
selected_deletion_fqns = selected_fqns - set(self._models)
1631+
16251632
expanded_restate_models = None
16261633
if restate_models is not None:
16271634
expanded_restate_models = model_selector.expand_model_selections(restate_models)
16281635

16291636
if (restate_models is not None and not expanded_restate_models) or (
1630-
backfill_models is not None and not backfill_models
1637+
backfill_models is not None and not backfill_models and not selected_deletion_fqns
16311638
):
16321639
raise PlanError(
16331640
"Selector did not return any models. Please check your model selection and try again."
@@ -1636,7 +1643,7 @@ def plan_builder(
16361643
if always_include_local_changes is None:
16371644
# default behaviour - if restatements are detected; we operate entirely out of state and ignore local changes
16381645
force_no_diff = restate_models is not None or (
1639-
backfill_models is not None and not backfill_models
1646+
backfill_models is not None and not backfill_models and not selected_deletion_fqns
16401647
)
16411648
else:
16421649
force_no_diff = not always_include_local_changes

sqlmesh/core/engine_adapter/base.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2920,7 +2920,11 @@ def _replace_by_key(
29202920
target_columns_to_types = self.columns(target_table)
29212921

29222922
temp_table = self._get_temp_table(target_table)
2923-
key_exp = exp.func("CONCAT_WS", "'__SQLMESH_DELIM__'", *key) if len(key) > 1 else key[0]
2923+
key_exp = (
2924+
exp.func("CONCAT_WS", "'__SQLMESH_DELIM__'", *key, dialect=self.dialect)
2925+
if len(key) > 1
2926+
else key[0]
2927+
)
29242928
column_names = list(target_columns_to_types or [])
29252929

29262930
with self.transaction():

sqlmesh/core/engine_adapter/clickhouse.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,11 @@ def _replace_by_key(
423423
source_columns=source_columns,
424424
)
425425

426-
key_exp = exp.func("CONCAT_WS", "'__SQLMESH_DELIM__'", *key) if len(key) > 1 else key[0]
426+
key_exp = (
427+
exp.func("CONCAT_WS", "'__SQLMESH_DELIM__'", *key, dialect=self.dialect)
428+
if len(key) > 1
429+
else key[0]
430+
)
427431

428432
self._insert_overwrite_by_condition(
429433
target_table,

sqlmesh/core/environment.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ def _sanitize_name(cls, v: str) -> str:
5656
@classmethod
5757
def _validate_boolean_field(cls, v: t.Any, info: ValidationInfo) -> bool:
5858
if v is None:
59-
return info.field_name == "normalize_name"
59+
# Pydantic 2.13+ sets field_name to None during model_validate_json()
60+
return (info.field_name or "") == "normalize_name"
6061
return bool(v)
6162

6263
@t.overload

sqlmesh/core/metric/definition.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from sqlmesh.core.node import str_or_exp_to_str
1111
from sqlmesh.utils import UniqueKeyDict
1212
from sqlmesh.utils.errors import ConfigError
13-
from sqlmesh.utils.pydantic import PydanticModel, ValidationInfo, field_validator
13+
from sqlmesh.utils.pydantic import PydanticModel, ValidationInfo, field_validator, validation_data
1414

1515
MeasureAndDimTables = t.Tuple[str, t.Tuple[str, ...]]
1616

@@ -89,7 +89,7 @@ def _string_validator(cls, v: t.Any) -> t.Optional[str]:
8989
@field_validator("expression", mode="before")
9090
def _validate_expression(cls, v: t.Any, info: ValidationInfo) -> exp.Expr:
9191
if isinstance(v, str):
92-
dialect = info.data.get("dialect")
92+
dialect = validation_data(info).get("dialect")
9393
return d.parse_one(v, dialect=dialect)
9494
if isinstance(v, exp.Expr):
9595
return v

sqlmesh/core/model/common.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,13 @@
2121
prepare_env,
2222
serialize_env,
2323
)
24-
from sqlmesh.utils.pydantic import PydanticModel, ValidationInfo, field_validator, get_dialect
24+
from sqlmesh.utils.pydantic import (
25+
PydanticModel,
26+
ValidationInfo,
27+
field_validator,
28+
get_dialect,
29+
validation_data,
30+
)
2531

2632
if t.TYPE_CHECKING:
2733
from sqlglot.dialects.dialect import DialectType
@@ -479,7 +485,7 @@ def parse_expression(
479485
if callable(v):
480486
return v
481487

482-
dialect = info.data.get("dialect") if info else ""
488+
dialect = validation_data(info).get("dialect") if info else ""
483489

484490
if isinstance(v, list):
485491
return [
@@ -519,7 +525,7 @@ def parse_properties(
519525
if v is None:
520526
return v
521527

522-
dialect = info.data.get("dialect") if info else ""
528+
dialect = validation_data(info).get("dialect") if info else ""
523529

524530
if isinstance(v, str):
525531
v = d.parse_one(v, dialect=dialect)
@@ -557,8 +563,9 @@ def default_catalog(cls: t.Type, v: t.Any) -> t.Optional[str]:
557563

558564

559565
def depends_on(cls: t.Type, v: t.Any, info: ValidationInfo) -> t.Optional[t.Set[str]]:
560-
dialect = info.data.get("dialect")
561-
default_catalog = info.data.get("default_catalog")
566+
data = validation_data(info)
567+
dialect = data.get("dialect")
568+
default_catalog = data.get("default_catalog")
562569

563570
if isinstance(v, exp.Paren):
564571
v = v.unnest()

sqlmesh/core/model/definition.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1158,11 +1158,7 @@ def _audit_metadata_hash_values(self) -> t.List[str]:
11581158

11591159
for audit_name, audit_args in sorted(self.audits, key=lambda a: a[0]):
11601160
metadata.append(audit_name)
1161-
if audit_name in BUILT_IN_AUDITS:
1162-
for arg_name, arg_value in audit_args.items():
1163-
metadata.append(arg_name)
1164-
metadata.append(gen(arg_value))
1165-
else:
1161+
if audit_name not in BUILT_IN_AUDITS:
11661162
audit = self.audit_definitions[audit_name]
11671163
metadata.extend(
11681164
[
@@ -1172,6 +1168,9 @@ def _audit_metadata_hash_values(self) -> t.List[str]:
11721168
str(audit.blocking),
11731169
]
11741170
)
1171+
for arg_name, arg_value in audit_args.items():
1172+
metadata.append(arg_name)
1173+
metadata.append(gen(arg_value))
11751174

11761175
return metadata
11771176

sqlmesh/core/model/kind.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -786,7 +786,7 @@ def data_hash_values(self) -> t.List[t.Optional[str]]:
786786
gen(self.valid_to_name),
787787
str(self.invalidate_hard_deletes),
788788
self.time_data_type.sql(self.dialect),
789-
gen(self.batch_size) if self.batch_size is not None else None,
789+
str(self.batch_size) if self.batch_size is not None else None,
790790
]
791791

792792
@property

0 commit comments

Comments
 (0)