Skip to content

Commit 74ea5e3

Browse files
committed
Make ambiguousprojection a default sqlmesh linter rule in init
1 parent 0bf130a commit 74ea5e3

File tree

5 files changed

+35
-14
lines changed

5 files changed

+35
-14
lines changed

sqlmesh/cli/project_init.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ def _gen_config(
114114
rules:
115115
- ambiguousorinvalidcolumn
116116
- invalidselectstarexpansion
117+
- noambiguousprojections
117118
""",
118119
ProjectTemplate.DBT: f"""# --- Virtual Data Environment Mode ---
119120
# Enable Virtual Data Environments (VDE) for *development* environments.

sqlmesh/core/linter/definition.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
from __future__ import annotations
2-
import typing as t
3-
from sqlmesh.core.config.linter import LinterConfig
4-
from sqlmesh.core.model import Model
5-
from sqlmesh.utils.errors import raise_config_error
6-
from sqlmesh.core.console import LinterConsole, get_console
2+
73
import operator as op
4+
import typing as t
85
from collections.abc import Iterator, Iterable, Set, Mapping, Callable
96
from functools import reduce
10-
from sqlmesh.core.model import Model
11-
from sqlmesh.core.linter.rule import Rule, RuleViolation, Range, Fix
7+
8+
from sqlmesh.core.config.linter import LinterConfig
129
from sqlmesh.core.console import LinterConsole, get_console
10+
from sqlmesh.core.linter.rule import Rule, RuleViolation, Range, Fix
11+
from sqlmesh.core.model import Model
12+
from sqlmesh.utils.errors import raise_config_error
1313

1414
if t.TYPE_CHECKING:
1515
from sqlmesh.core.context import GenericContext
@@ -38,6 +38,12 @@ def __init__(
3838
self.rules = rules
3939
self.warn_rules = warn_rules
4040

41+
if overlapping := rules.intersection(warn_rules):
42+
overlapping_rules = ", ".join(rule for rule in overlapping)
43+
raise_config_error(
44+
f"Rules cannot simultaneously warn and raise an error: [{overlapping_rules}]"
45+
)
46+
4147
@classmethod
4248
def from_rules(cls, all_rules: RuleSet, config: LinterConfig) -> Linter:
4349
ignored_rules = select_rules(all_rules, config.ignored_rules)
@@ -46,12 +52,6 @@ def from_rules(cls, all_rules: RuleSet, config: LinterConfig) -> Linter:
4652
rules = select_rules(included_rules, config.rules)
4753
warn_rules = select_rules(included_rules, config.warn_rules)
4854

49-
if overlapping := rules.intersection(warn_rules):
50-
overlapping_rules = ", ".join(rule for rule in overlapping)
51-
raise_config_error(
52-
f"Rules cannot simultaneously warn and raise an error: [{overlapping_rules}]"
53-
)
54-
5555
return Linter(config.enabled, all_rules, rules, warn_rules)
5656

5757
def lint_model(

sqlmesh/core/linter/rules/builtin.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ def create_fix(self, model_name: str) -> t.Optional[Fix]:
275275

276276

277277
class NoAmbiguousProjections(Rule):
278-
"""All projections in a model must have unique, inferrable names or explicit aliases."""
278+
"""All projections in a model must have unique & inferrable names or explicit aliases."""
279279

280280
def check_model(self, model: Model) -> t.Optional[RuleViolation]:
281281
query = model.render_query()

tests/cli/test_cli.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -982,6 +982,7 @@ def test_dlt_filesystem_pipeline(tmp_path):
982982
" rules:\n"
983983
" - ambiguousorinvalidcolumn\n"
984984
" - invalidselectstarexpansion\n"
985+
" - noambiguousprojections\n"
985986
)
986987

987988
with open(config_path) as file:
@@ -1048,6 +1049,7 @@ def test_dlt_pipeline(runner, tmp_path):
10481049
rules:
10491050
- ambiguousorinvalidcolumn
10501051
- invalidselectstarexpansion
1052+
- noambiguousprojections
10511053
"""
10521054

10531055
with open(tmp_path / "config.yaml") as file:
@@ -1990,6 +1992,7 @@ def test_init_project_engine_configs(tmp_path):
19901992
rules:
19911993
- ambiguousorinvalidcolumn
19921994
- invalidselectstarexpansion
1995+
- noambiguousprojections
19931996
"""
19941997

19951998
with open(tmp_path / "config.yaml") as file:

tests/core/test_context.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3117,3 +3117,20 @@ def test_plan_no_start_configured():
31173117
match=r"Model '.*xvg.*': Start date / time .* can't be greater than end date / time .*\.\nSet the `start` attribute in your project config model defaults to avoid this issue",
31183118
):
31193119
context.plan("dev", execution_time="1999-01-05")
3120+
3121+
3122+
def test_lint_model_projections(tmp_path: Path):
3123+
init_example_project(tmp_path, engine_type="duckdb", dialect="duckdb")
3124+
3125+
context = Context(paths=tmp_path)
3126+
context.upsert_model(
3127+
load_sql_based_model(
3128+
parse("""MODEL(name sqlmesh_example.m); SELECT 1 AS x, 2 AS x"""),
3129+
default_catalog="db",
3130+
)
3131+
)
3132+
3133+
config_err = "Linter detected errors in the code. Please fix them before proceeding."
3134+
3135+
with pytest.raises(LinterError, match=config_err):
3136+
prod_plan = context.plan(no_prompts=True, auto_apply=True)

0 commit comments

Comments
 (0)