Skip to content

Commit 88235cc

Browse files
committed
making it key for model
1 parent a5d2c9f commit 88235cc

File tree

4 files changed

+44
-40
lines changed

4 files changed

+44
-40
lines changed

sqlmesh/core/context.py

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,13 @@
4040
import time
4141
import traceback
4242
import typing as t
43+
from datetime import datetime
4344
from functools import cached_property
4445
from io import StringIO
4546
from itertools import chain
4647
from pathlib import Path
4748
from shutil import rmtree
4849
from types import MappingProxyType
49-
from datetime import datetime
5050

5151
from sqlglot import Dialect, exp
5252
from sqlglot.helper import first
@@ -63,6 +63,7 @@
6363
)
6464
from sqlmesh.core.config.connection import ConnectionConfig
6565
from sqlmesh.core.config.loader import C
66+
from sqlmesh.core.config.model import ModelDefaultsConfig
6667
from sqlmesh.core.config.root import RegexKeyDict
6768
from sqlmesh.core.console import get_console
6869
from sqlmesh.core.context_diff import ContextDiff
@@ -76,24 +77,23 @@
7677
)
7778
from sqlmesh.core.engine_adapter import EngineAdapter
7879
from sqlmesh.core.environment import Environment, EnvironmentNamingInfo, EnvironmentStatements
79-
from sqlmesh.core.loader import Loader
8080
from sqlmesh.core.linter.definition import AnnotatedRuleViolation, Linter
8181
from sqlmesh.core.linter.rules import BUILTIN_RULES
82+
from sqlmesh.core.loader import Loader
8283
from sqlmesh.core.macros import ExecutableOrMacro, macro
8384
from sqlmesh.core.metric import Metric, rewrite
8485
from sqlmesh.core.model import Model, update_model_schemas
85-
from sqlmesh.core.config.model import ModelDefaultsConfig
8686
from sqlmesh.core.notification_target import (
8787
NotificationEvent,
8888
NotificationTarget,
8989
NotificationTargetManager,
9090
)
91-
from sqlmesh.core.plan import Plan, PlanBuilder, SnapshotIntervals, PlanExplainer
91+
from sqlmesh.core.plan import Plan, PlanBuilder, PlanExplainer, SnapshotIntervals
9292
from sqlmesh.core.plan.definition import UserProvidedFlags
9393
from sqlmesh.core.reference import ReferenceGraph
94-
from sqlmesh.core.scheduler import Scheduler, CompletionStatus
94+
from sqlmesh.core.scheduler import CompletionStatus, Scheduler
9595
from sqlmesh.core.schema_loader import create_external_models_file
96-
from sqlmesh.core.selector import Selector, NativeSelector
96+
from sqlmesh.core.selector import NativeSelector, Selector
9797
from sqlmesh.core.snapshot import (
9898
DeployabilityIndex,
9999
Snapshot,
@@ -111,42 +111,42 @@
111111
)
112112
from sqlmesh.core.table_diff import TableDiff
113113
from sqlmesh.core.test import (
114-
ModelTextTestResult,
115114
ModelTestMetadata,
115+
ModelTextTestResult,
116116
generate_test,
117117
run_tests,
118118
)
119119
from sqlmesh.core.user import User
120120
from sqlmesh.utils import UniqueKeyDict, Verbosity
121121
from sqlmesh.utils.concurrency import concurrent_apply_to_values
122+
from sqlmesh.utils.config import print_config
122123
from sqlmesh.utils.dag import DAG
123124
from sqlmesh.utils.date import (
124125
TimeLike,
125-
to_timestamp,
126126
format_tz_datetime,
127-
now_timestamp,
127+
make_exclusive,
128128
now,
129+
now_timestamp,
129130
to_datetime,
130-
make_exclusive,
131+
to_timestamp,
131132
)
132133
from sqlmesh.utils.errors import (
133134
CircuitBreakerError,
134135
ConfigError,
136+
LinterError,
135137
PlanError,
136138
SQLMeshError,
137139
UncategorizedPlanError,
138-
LinterError,
139140
)
140-
from sqlmesh.utils.config import print_config
141141
from sqlmesh.utils.jinja import JinjaMacroRegistry
142142

143143
if t.TYPE_CHECKING:
144144
import pandas as pd
145145
from typing_extensions import Literal
146146

147147
from sqlmesh.core.engine_adapter._typing import (
148-
BigframeSession,
149148
DF,
149+
BigframeSession,
150150
PySparkDataFrame,
151151
PySparkSession,
152152
SnowparkSession,
@@ -389,6 +389,7 @@ def __init__(
389389
self._standalone_audits: UniqueKeyDict[str, StandaloneAudit] = UniqueKeyDict(
390390
"standaloneaudits"
391391
)
392+
self._models_with_tests: t.Set[str] = set()
392393
self._macros: UniqueKeyDict[str, ExecutableOrMacro] = UniqueKeyDict("macros")
393394
self._metrics: UniqueKeyDict[str, Metric] = UniqueKeyDict("metrics")
394395
self._jinja_macros = JinjaMacroRegistry()
@@ -638,6 +639,7 @@ def load(self, update_schemas: bool = True) -> GenericContext[C]:
638639
self._requirements.update(project.requirements)
639640
self._excluded_requirements.update(project.excluded_requirements)
640641
self._environment_statements.extend(project.environment_statements)
642+
self._models_with_tests.update(project.models_with_tests)
641643

642644
config = loader.config
643645
self._linters[config.project] = Linter.from_rules(
@@ -1040,6 +1042,11 @@ def standalone_audits(self) -> MappingProxyType[str, StandaloneAudit]:
10401042
"""Returns all registered standalone audits in this context."""
10411043
return MappingProxyType(self._standalone_audits)
10421044

1045+
@property
1046+
def models_with_tests(self) -> t.Set[str]:
1047+
"""Returns all models with tests in this context."""
1048+
return self._models_with_tests
1049+
10431050
@property
10441051
def snapshots(self) -> t.Dict[str, Snapshot]:
10451052
"""Generates and returns snapshots based on models registered in this context.

sqlmesh/core/linter/rules/builtin.py

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
import typing as t
66

7-
from ruamel.yaml import YAML
87
from sqlglot.expressions import Star
98
from sqlglot.helper import subclasses
109

@@ -138,25 +137,7 @@ def check_model(self, model: Model) -> t.Optional[RuleViolation]:
138137
if isinstance(model, ExternalModel):
139138
return None
140139

141-
test_dir = self.context.path / "tests"
142-
found_test = False
143-
144-
yaml_parser = YAML(typ="safe")
145-
for test_file in test_dir.rglob("*.yaml"):
146-
try:
147-
test_data = yaml_parser.load(test_file) or {}
148-
except Exception:
149-
# Skip files with Jinja templating or other parse errors
150-
continue
151-
152-
for _, test_config in test_data.items():
153-
if test_config.get("model") == model.name:
154-
found_test = True
155-
break
156-
if found_test:
157-
break
158-
159-
if not found_test:
140+
if model.name not in self.context.models_with_tests:
160141
return self.violation(
161142
violation_msg=f"Model {model.name} is missing unit test(s). Please add in the tests/ directory."
162143
)

sqlmesh/core/loader.py

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from __future__ import annotations
22

33
import abc
4+
import concurrent.futures
45
import glob
56
import itertools
67
import linecache
@@ -10,20 +11,19 @@
1011
from collections import Counter, defaultdict
1112
from dataclasses import dataclass
1213
from pathlib import Path
13-
from pydantic import ValidationError
14-
import concurrent.futures
1514

16-
from sqlglot.errors import SqlglotError
15+
from pydantic import ValidationError
1716
from sqlglot import exp
17+
from sqlglot.errors import SqlglotError
1818
from sqlglot.helper import subclasses
1919

2020
from sqlmesh.core import constants as c
2121
from sqlmesh.core.audit import Audit, ModelAudit, StandaloneAudit, load_multiple_audits
2222
from sqlmesh.core.console import Console
2323
from sqlmesh.core.dialect import parse
2424
from sqlmesh.core.environment import EnvironmentStatements
25-
from sqlmesh.core.linter.rule import Rule
2625
from sqlmesh.core.linter.definition import RuleSet
26+
from sqlmesh.core.linter.rule import Rule
2727
from sqlmesh.core.macros import MacroRegistry, macro
2828
from sqlmesh.core.metric import Metric, MetricMeta, expand_metrics, load_metric_ddl
2929
from sqlmesh.core.model import (
@@ -40,10 +40,10 @@
4040
from sqlmesh.utils.errors import ConfigError
4141
from sqlmesh.utils.jinja import JinjaMacroRegistry, MacroExtractor
4242
from sqlmesh.utils.metaprogramming import import_python_file
43-
from sqlmesh.utils.pydantic import validation_error_message
4443
from sqlmesh.utils.process import create_process_pool_executor
45-
from sqlmesh.utils.yaml import YAML, load as yaml_load
46-
44+
from sqlmesh.utils.pydantic import validation_error_message
45+
from sqlmesh.utils.yaml import YAML
46+
from sqlmesh.utils.yaml import load as yaml_load
4747

4848
if t.TYPE_CHECKING:
4949
from sqlmesh.core.context import GenericContext
@@ -64,6 +64,8 @@ class LoadedProject:
6464
excluded_requirements: t.Set[str]
6565
environment_statements: t.List[EnvironmentStatements]
6666
user_rules: RuleSet
67+
model_test_metadata: t.List[ModelTestMetadata]
68+
models_with_tests: t.Set[str]
6769

6870

6971
class CacheBase(abc.ABC):
@@ -243,6 +245,14 @@ def load(self) -> LoadedProject:
243245

244246
user_rules = self._load_linting_rules()
245247

248+
model_test_metadata = self.load_model_tests()
249+
250+
models_with_tests = {
251+
model_test_metadata.model_name for model_test_metadata in model_test_metadata
252+
}
253+
254+
self._models_with_tests = models_with_tests
255+
246256
project = LoadedProject(
247257
macros=macros,
248258
jinja_macros=jinja_macros,
@@ -254,6 +264,8 @@ def load(self) -> LoadedProject:
254264
excluded_requirements=excluded_requirements,
255265
environment_statements=environment_statements,
256266
user_rules=user_rules,
267+
model_test_metadata=model_test_metadata,
268+
models_with_tests=models_with_tests,
257269
)
258270
return project
259271

sqlmesh/core/test/discovery.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ class ModelTestMetadata(PydanticModel):
2020
def fully_qualified_test_name(self) -> str:
2121
return f"{self.path}::{self.test_name}"
2222

23+
@property
24+
def model_name(self) -> str:
25+
return self.body["model"]
26+
2327
def __hash__(self) -> int:
2428
return self.fully_qualified_test_name.__hash__()
2529

0 commit comments

Comments
 (0)