Skip to content

Commit 7d00aa5

Browse files
authored
Merge branch 'main' into fix/clickhouse-primary-key-paren
2 parents 99e7bf7 + aebfac9 commit 7d00aa5

5 files changed

Lines changed: 42 additions & 3 deletions

File tree

sqlmesh/core/model/kind.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,8 @@ def to_property(self, dialect: str = "") -> exp.Property:
341341
@classmethod
342342
def create(cls, v: t.Any, dialect: str) -> Self:
343343
if isinstance(v, exp.Tuple):
344+
if not v.expressions:
345+
raise ConfigError("Time Column cannot be empty.")
344346
column_expr = v.expressions[0]
345347
column = (
346348
exp.column(column_expr) if isinstance(column_expr, exp.Identifier) else column_expr

sqlmesh/utils/pydantic.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ def _formatted_validation_errors(error: pydantic.ValidationError) -> t.List[str]
242242
for e in error.errors():
243243
msg = e["msg"]
244244
loc: t.Optional[t.Tuple] = e.get("loc")
245-
loc_str = ".".join(loc) if loc else None
245+
loc_str = ".".join(str(p) for p in loc) if loc else None
246246
result.append(f"Invalid field '{loc_str}':\n {msg}" if loc_str else msg)
247247
return result
248248

tests/core/test_config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -702,7 +702,7 @@ def test_load_model_defaults_validation_statements(tmp_path):
702702
"""
703703
)
704704

705-
with pytest.raises(TypeError, match=r"expected str instance, int found"):
705+
with pytest.raises(ConfigError, match=r"Invalid field 'model_defaults\.pre_statements\.0"):
706706
config = load_config_from_paths(
707707
Config,
708708
project_paths=[config_path],

tests/core/test_model.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2680,6 +2680,21 @@ def test_time_column():
26802680
assert model.time_column.format == "%Y-%m"
26812681
assert model.time_column.expression == d.parse_one("(\"ds\", '%Y-%m')")
26822682

2683+
expressions = d.parse(
2684+
"""
2685+
MODEL (
2686+
name db.table,
2687+
kind INCREMENTAL_BY_TIME_RANGE(
2688+
time_column ()
2689+
)
2690+
);
2691+
2692+
SELECT col::text, ds::text
2693+
"""
2694+
)
2695+
with pytest.raises(ConfigError, match="Time Column cannot be empty."):
2696+
load_sql_based_model(expressions)
2697+
26832698

26842699
def test_default_time_column():
26852700
expressions = d.parse(

tests/utils/test_pydantic.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,14 @@
22
import pytest
33
from functools import cached_property
44

5+
import pydantic
6+
57
from sqlmesh.utils.date import TimeLike, to_date, to_datetime
6-
from sqlmesh.utils.pydantic import PydanticModel, get_concrete_types_from_typehint
8+
from sqlmesh.utils.pydantic import (
9+
PydanticModel,
10+
get_concrete_types_from_typehint,
11+
validation_error_message,
12+
)
713

814

915
def test_datetime_date_serialization() -> None:
@@ -87,3 +93,19 @@ class TestModel(PydanticModel):
8793
)
8894
def test_get_concrete_types_from_typehint(input: t.Any, output: set[type]) -> None:
8995
assert get_concrete_types_from_typehint(input) == output
96+
97+
98+
def test_validation_error_message_with_list_index_location() -> None:
99+
class Inner(PydanticModel):
100+
x: int
101+
102+
class Outer(PydanticModel):
103+
items: t.List[Inner]
104+
105+
with pytest.raises(pydantic.ValidationError) as ex:
106+
Outer(items=[{"x": "not_an_int"}])
107+
108+
# The error is located at a list index, so pydantic's loc mixes str field
109+
# names with an int sequence index (e.g. ("items", 0, "x")).
110+
message = validation_error_message(ex.value, "Invalid config:")
111+
assert "Invalid field 'items.0.x'" in message

0 commit comments

Comments
 (0)