Skip to content

Commit 0761ce6

Browse files
committed
temp [ci skip]
1 parent 8890694 commit 0761ce6

File tree

6 files changed

+99
-34
lines changed

6 files changed

+99
-34
lines changed

examples/sushi/models/customers.sql

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@ MODEL (
22
name sushi.customers,
33
kind FULL,
44
owner jen,
5+
owners test,
56
cron '@daily',
67
tags (pii, fact),
78
grain customer_id,
9+
grains why,
810
description 'Sushi customer data',
911
column_descriptions (
10-
customer_id = 'customer_id uniquely identifies customers'
12+
customer_id = 'customer_id uniquely i:wdentifies customers'
1113
)
1214
);
1315

sqlmesh/core/linter/helpers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ def read_range_from_file(file: Path, text_range: Range) -> str:
118118

119119
def get_range_of_model_block(
120120
sql: str,
121-
dialect: str,
121+
dialect: t.Optional[str] = None,
122122
) -> t.Optional[Range]:
123123
"""
124124
Get the range of the model block in an SQL file.

sqlmesh/core/model/common.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -275,9 +275,12 @@ def validate_extra_and_required_fields(
275275
) -> None:
276276
missing_required_fields = klass.missing_required_fields(provided_fields)
277277
if missing_required_fields:
278-
if path is None:
279-
raise_config_error(
280-
raise ModelBlockFieldValidationMissingFieldsError(path, missing_required_fields)
278+
if path is not None:
279+
raise ModelBlockFieldValidationMissingFieldsError(path, missing_required_fields)
280+
field_names = "'" + "', '".join(missing_required_fields) + "'"
281+
raise_config_error(
282+
f"Please add required field{'s' if len(missing_required_fields) > 1 else ''} {field_names} to the {entity_name}."
283+
)
281284

282285
extra_fields = klass.extra_fields(provided_fields)
283286
if extra_fields:

sqlmesh/lsp/errors.py

Lines changed: 70 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,88 @@
1-
from lsprotocol.types import Diagnostic
2-
from sqlmesh.utils.errors import ConfigError, ModeBlockExtraFields, ModelBlockFieldValidationMissingFieldsError
1+
from lsprotocol.types import Diagnostic, DiagnosticSeverity, Range, Position
2+
3+
from sqlmesh.core.linter.helpers import get_range_of_model_block
4+
from sqlmesh.lsp.helpers import to_lsp_range
5+
from sqlmesh.lsp.uri import URI
6+
from sqlmesh.utils.errors import (
7+
ConfigError,
8+
ModeBlockExtraFields,
9+
ModelBlockFieldValidationMissingFieldsError,
10+
)
311
import typing as t
412

5-
type ContextFailedError = str | ConfigError | ModeBlockExtraFields | ModelBlockFieldValidationMissingFieldsError
13+
type ContextFailedError = (
14+
str | ConfigError | ModeBlockExtraFields | ModelBlockFieldValidationMissingFieldsError
15+
)
16+
617

7-
def contextErrorToDiagnostic(error: Exception,) -> t.Tuple[t.Optional[t.Tuple[str, Diagnostic]], ContextFailedError]:
18+
def contextErrorToDiagnostic(
19+
error: Exception,
20+
) -> t.Tuple[t.Optional[t.Tuple[str, Diagnostic]], ContextFailedError]:
821
if isinstance(error, ModelBlockFieldValidationMissingFieldsError):
922
return missingErrorToDiagnostic(error), error
10-
if isinstance(error, ModeBlockExtraFields)
23+
if isinstance(error, ModeBlockExtraFields):
1124
return extraFieldsErrorToDiagnostic(error), error
1225
if isinstance(error, ConfigError):
1326
return configErrorToDiagnostic(error), error
1427
return None, str(error)
1528

1629

1730
def missingErrorToDiagnostic(
18-
error: ModelBlockFieldValidationMissingFieldsError,
19-
) ->t.Optional[t.Tuple[str, Diagnostic]]:
20-
raise NotImplementedError()
31+
error: ModelBlockFieldValidationMissingFieldsError,
32+
) -> t.Optional[t.Tuple[str, Diagnostic]]:
33+
if error.location is None:
34+
return None
35+
uri = URI.from_path(error.location).value
36+
with open(error.location, "r") as file:
37+
content = file.read()
38+
model_block = get_range_of_model_block(content)
39+
if model_block is None:
40+
return None
41+
return uri, Diagnostic(
42+
message=str(error),
43+
range=to_lsp_range(model_block),
44+
severity=DiagnosticSeverity.Error,
45+
source="SQLMesh",
46+
)
47+
2148

2249
def extraFieldsErrorToDiagnostic(
23-
error: ModeBlockExtraFields,
50+
error: ModeBlockExtraFields,
2451
) -> t.Optional[t.Tuple[str, Diagnostic]]:
25-
raise NotImplementedError()
52+
if error.location is None:
53+
return None
54+
uri = URI.from_path(error.location).value
55+
with open(error.location, "r") as file:
56+
content = file.read()
57+
model_block = get_range_of_model_block(content)
58+
if model_block is None:
59+
return None
60+
return uri, Diagnostic(
61+
message=str(error),
62+
range=to_lsp_range(model_block),
63+
severity=DiagnosticSeverity.Error,
64+
source="SQLMesh",
65+
)
2666

27-
def configErrorToDiagnostic(
28-
error: ConfigError,
29-
) ->t.Optional[t.Tuple[str, Diagnostic]]:
30-
return Diagnostic(
3167

68+
def configErrorToDiagnostic(
69+
error: ConfigError,
70+
) -> t.Optional[t.Tuple[str, Diagnostic]]:
71+
if error.location is None:
72+
return None
73+
uri = URI.from_path(error.location).value
74+
return uri, Diagnostic(
75+
range=Range(
76+
start=Position(
77+
line=0,
78+
character=0,
79+
),
80+
end=Position(
81+
line=0,
82+
character=0,
83+
),
84+
),
85+
message=str(error),
86+
severity=DiagnosticSeverity.Error,
87+
source="SQLMesh",
3288
)
33-
raise NotImplementedError()
34-

sqlmesh/lsp/main.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
)
5858
from sqlmesh.lsp.rename import prepare_rename, rename_symbol, get_document_highlights
5959
from sqlmesh.lsp.uri import URI
60-
from sqlmesh.utils.errors import ConfigError, ModelBlockFieldValidationMissingFieldsError, ModeBlockExtraFields
60+
from sqlmesh.utils.errors import ConfigError
6161
from web.server.api.endpoints.lineage import column_lineage, model_lineage
6262
from web.server.api.endpoints.models import get_models
6363
from typing import Union
@@ -894,9 +894,10 @@ def _create_lsp_context(
894894
return self.context_state.lsp_context
895895
except Exception as e:
896896
# Only show the error message once
897-
(uri, diagnostic), error = contextErrorToDiagnostic(e)
897+
diagnostic, error = contextErrorToDiagnostic(e)
898898
if diagnostic:
899-
ls.publish_diagnostics(uri, [diagnostic])
899+
uri, lsp_diagnostic = diagnostic
900+
ls.publish_diagnostics(uri, [lsp_diagnostic])
900901

901902
# Store the error in context state such that later requests can
902903
# show the actual error. Try to preserve any partially loaded context

sqlmesh/utils/errors.py

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,27 +52,32 @@ def message(missing_fields: t.Set[str]) -> str:
5252

5353
class ModeBlockExtraFields(ConfigError):
5454
"""Raised when there are extra fields in a model block that are not defined in the model schema. If there are close
55-
matches, this tries to recommend them"""
55+
matches, this tries to recommend them"""
5656

57-
def __init__(self, path: Path, extra_fields: t.Dict[str, t.Optional[None]]) -> None:
57+
def __init__(self, path: t.Optional[Path], extra_fields: t.Dict[str, t.Optional[str]]) -> None:
5858
super().__init__(
5959
self.message(extra_fields),
6060
path,
6161
)
6262
self.extra_fields = extra_fields
6363

6464
@staticmethod
65-
def message(extra_fields: t.Dict[str, t.Optional[None]]) -> str:
66-
if len(extra_with_close_match) == 1:
67-
similar_msg = (
68-
". Did you mean " + "'" + "', '".join(extra_with_close_match.values()) + "'?"
69-
)
70-
else:
65+
def message(extra_fields: t.Dict[str, t.Optional[str]]) -> str:
66+
extra_field_names = "'" + "', '".join(extra_fields.keys()) + "'"
67+
68+
close_matches = {field: match for field, match in extra_fields.items() if match is not None}
69+
70+
if len(close_matches) == 1:
71+
similar_msg = ". Did you mean '" + list(close_matches.values())[0] + "'?"
72+
elif close_matches:
7173
similar = [
7274
f"- {field}: Did you mean '{match}'?" for field, match in close_matches.items()
7375
]
74-
similar_msg = "\n\n " + "\n ".join(similar) if similar else ""
75-
return f"Invalid field name{'s' if len(extra_fields) > 1 else ''} present in the {entity_name}: {extra_field_names}{similar_msg}"
76+
similar_msg = "\n\n " + "\n ".join(similar)
77+
else:
78+
similar_msg = ""
79+
80+
return f"Invalid field name{'s' if len(extra_fields) > 1 else ''} present in the model block: {extra_field_names}{similar_msg}"
7681

7782

7883
class MissingDependencyError(SQLMeshError):

0 commit comments

Comments
 (0)