Skip to content

Commit 3b37622

Browse files
committed
temp [ci skip]
1 parent f26352a commit 3b37622

File tree

3 files changed

+58
-20
lines changed

3 files changed

+58
-20
lines changed

sqlmesh/core/model/common.py

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
from sqlmesh.core import dialect as d
1414
from sqlmesh.core.macros import MacroRegistry, MacroStrTemplate
1515
from sqlmesh.utils import str_to_bool
16-
from sqlmesh.utils.errors import ConfigError, SQLMeshError, raise_config_error
16+
from sqlmesh.utils.errors import ConfigError, SQLMeshError, raise_config_error, \
17+
ModelBlockFieldValidationMissingFieldsError, ModeBlockExtraFields
1718
from sqlmesh.utils.metaprogramming import (
1819
Executable,
1920
SqlValue,
@@ -269,34 +270,29 @@ def validate_extra_and_required_fields(
269270
) -> None:
270271
missing_required_fields = klass.missing_required_fields(provided_fields)
271272
if missing_required_fields:
272-
field_names = "'" + "', '".join(missing_required_fields) + "'"
273-
raise_config_error(
274-
f"Please add required field{'s' if len(missing_required_fields) > 1 else ''} {field_names} to the {entity_name}."
273+
raise ModelBlockFieldValidationMissingFieldsError(
274+
path, missing_required_fields
275275
)
276276

277277
extra_fields = klass.extra_fields(provided_fields)
278278
if extra_fields:
279279
extra_field_names = "'" + "', '".join(extra_fields) + "'"
280280

281281
all_fields = klass.all_fields()
282-
close_matches = {}
282+
extra_with_close_match: t.Dict[str, t.Optional[str]] = {}
283283
for field in extra_fields:
284284
matches = get_close_matches(field, all_fields, n=1)
285285
if matches:
286-
close_matches[field] = matches[0]
286+
extra_with_close_match[field] = matches[0]
287+
else:
288+
extra_with_close_match[field] = None
289+
290+
if extra_with_close_match:
291+
raise ModeBlockExtraFields(
292+
path,
293+
extra_fields=extra_with_close_match,
294+
)
287295

288-
if len(close_matches) == 1:
289-
similar_msg = ". Did you mean " + "'" + "', '".join(close_matches.values()) + "'?"
290-
else:
291-
similar = [
292-
f"- {field}: Did you mean '{match}'?" for field, match in close_matches.items()
293-
]
294-
similar_msg = "\n\n " + "\n ".join(similar) if similar else ""
295-
296-
raise_config_error(
297-
f"Invalid field name{'s' if len(extra_fields) > 1 else ''} present in the {entity_name}: {extra_field_names}{similar_msg}",
298-
path,
299-
)
300296

301297

302298
def single_value_or_tuple(values: t.Sequence) -> exp.Identifier | exp.Tuple:

sqlmesh/core/model/kind.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1015,8 +1015,8 @@ def create_model_kind(v: t.Any, dialect: str, defaults: t.Dict[str, t.Any]) -> M
10151015
"The 'materialization' property is required for models of the CUSTOM kind"
10161016
)
10171017

1018-
# The below call will print a warning if a materialization with the given name doesn't exist
1019-
# we dont want to throw an error here because we still want Models with a CustomKind to be able
1018+
# The below call prints a warning if no materialization with the given name doesn't exist.
1019+
# We don't throw an error here because we still want Models with a CustomKind to be able
10201020
# to be serialized / deserialized in contexts where the custom materialization class may not be available,
10211021
# such as in HTTP request handlers
10221022
custom_materialization = get_custom_materialization_type(

sqlmesh/utils/errors.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,48 @@ def __init__(self, message: str | Exception, location: t.Optional[Path] = None)
3131
if location:
3232
self.location = Path(location) if isinstance(location, str) else location
3333

34+
class ModelBlockFieldValidationMissingFieldsError(ConfigError):
35+
"""Raised when required fields are missing from a model block."""
36+
missing_fields: t.Set[str]
37+
38+
def __init__(self, path: Path, missing_fields: t.Set[str]) -> None:
39+
super().__init__(
40+
self.message(missing_fields),
41+
path,
42+
)
43+
self.missing_fields = missing_fields
44+
45+
@staticmethod
46+
def message(self, missing_fields: t.List[str]) -> str:
47+
field_names = "'" + "', '".join(self.missing_fields) + "'"
48+
return f"Please add required field{'s' if len(self.missing_fields) > 1 else ''} {field_names} to the model block."
49+
50+
class ModeBlockExtraFields(ConfigError):
51+
"""Raised when there are extra fields in a model block that are not defined in the model schema. If there are close
52+
matches this tries to recommend them"""
53+
54+
def __init__(self, path: Path, extra_fields: t.Dict[str, t.Optional[None]]) -> None:
55+
super().__init__(
56+
self.message(extra_fields),
57+
path,
58+
)
59+
self.extra_fields = extra_fields
60+
61+
@staticmethod
62+
def message(extra_fields: t.Dict[str, t.Optional[None]]) -> str:
63+
if len(extra_with_close_match) == 1:
64+
similar_msg = ". Did you mean " + "'" + "', '".join(extra_with_close_match.values()) + "'?"
65+
else:
66+
similar = [
67+
f"- {field}: Did you mean '{match}'?" for field, match in close_matches.items()
68+
]
69+
similar_msg = "\n\n " + "\n ".join(similar) if similar else ""
70+
71+
raise_config_error(
72+
f"Invalid field name{'s' if len(extra_fields) > 1 else ''} present in the {entity_name}: {extra_field_names}{similar_msg}",
73+
path,
74+
)
75+
3476

3577
class MissingDependencyError(SQLMeshError):
3678
"""Local environment is missing a required dependency for the given operation"""

0 commit comments

Comments
 (0)