From 5b7da15d325ed0ba90bc34c7d4eaf1c88ae3e9ad Mon Sep 17 00:00:00 2001 From: Kevin Longe <273747162+kvlonge@users.noreply.github.com> Date: Wed, 23 Sep 2026 10:45:50 +0100 Subject: [PATCH 1/2] perf: reuse compiler declaration scope and file reads in SQL rules --- .../cli/commands/_helpers/compile/pipeline.py | 1 + .../compile/main/_build_compile_inputs.py | 1 + .../compile/main/sql_expansion_context.py | 21 ++++--- src/sqlbuild/compiler/compile/models.py | 1 + .../planner/_helpers/sql_tests/comments.py | 2 + src/sqlbuild/lint/_helpers/expansion.py | 3 + src/sqlbuild/lint/_helpers/project_files.py | 15 ++++- .../lint/main/build_expansion_context.py | 11 +++- src/sqlbuild/lint/main/run_lint.py | 3 +- .../rule_engine/_helpers/run/rules.py | 51 +++++++++++++++-- .../rule_engine/classes/early_sql_lint.py | 11 +++- src/sqlbuild/rule_engine/main/run_rules.py | 9 ++- src/sqlbuild/rule_engine/models.py | 11 +++- .../sqlbuild/cli/commands/main/test_rules.py | 57 +++++++++++++++++++ 14 files changed, 176 insertions(+), 21 deletions(-) diff --git a/src/sqlbuild/cli/commands/_helpers/compile/pipeline.py b/src/sqlbuild/cli/commands/_helpers/compile/pipeline.py index 1fe21cd808..e8268fb2bf 100644 --- a/src/sqlbuild/cli/commands/_helpers/compile/pipeline.py +++ b/src/sqlbuild/cli/commands/_helpers/compile/pipeline.py @@ -204,6 +204,7 @@ def _analyze_compile_project( dialect=adapter.sql_analysis_dialect() or "generic", selected_keys=selected_keys if select or exclude else None, prepared_sql=early_lint.preparation, + expansion_reuse=early_lint.expansion_reuse, ) _ = complete_compile_phase( status=status, diff --git a/src/sqlbuild/compiler/compile/main/_build_compile_inputs.py b/src/sqlbuild/compiler/compile/main/_build_compile_inputs.py index b3a76d03b7..c70da831c5 100644 --- a/src/sqlbuild/compiler/compile/main/_build_compile_inputs.py +++ b/src/sqlbuild/compiler/compile/main/_build_compile_inputs.py @@ -235,6 +235,7 @@ def build_compile_inputs( diagnostics=diagnostics, external_sql_reference_resolver=external_sql_reference_resolver, scope_index=declaration_scope.index, + declaration_scope=declaration_scope, ) diff --git a/src/sqlbuild/compiler/compile/main/sql_expansion_context.py b/src/sqlbuild/compiler/compile/main/sql_expansion_context.py index 09b066ac2b..104000a4b7 100644 --- a/src/sqlbuild/compiler/compile/main/sql_expansion_context.py +++ b/src/sqlbuild/compiler/compile/main/sql_expansion_context.py @@ -39,6 +39,7 @@ def build_sql_expansion_context( value_renderer: TypedSqlValueRenderer, cli_vars: dict[str, object] | None = None, discovered_inputs: DiscoveredProjectInputs | None = None, + declaration_scope: DeclarationScopeBuild | None = None, ) -> SqlExpansionContext: """Assemble project vars, macros and declarations for SQL expansion.""" @@ -53,13 +54,10 @@ def build_sql_expansion_context( target_config=None, cli_vars={} if cli_vars is None else cli_vars, ) - loaded_macros: dict[str, LoadedMacro] = load_project_macros( - effective_discovered_inputs.macro_files - ) - declaration_scope: DeclarationScopeBuild = build_declaration_scope( - discovered_inputs=effective_discovered_inputs, - loaded_macros=loaded_macros, + scope: DeclarationScopeBuild = declaration_scope or _build_declaration_scope( + discovered_inputs=effective_discovered_inputs ) + loaded_macros: dict[str, LoadedMacro] = scope.loaded_macros enums: dict[str, EnumDeclaration] constants: dict[str, ConstantDeclaration] enums, constants = build_public_declaration_indexes( @@ -99,5 +97,14 @@ def build_sql_expansion_context( declaration_override=None, ), local_declarations=local_declarations, - declaration_resolver=declaration_scope.resolver, + declaration_resolver=scope.resolver, + ) + + +def _build_declaration_scope( + *, discovered_inputs: DiscoveredProjectInputs +) -> DeclarationScopeBuild: + return build_declaration_scope( + discovered_inputs=discovered_inputs, + loaded_macros=load_project_macros(discovered_inputs.macro_files), ) diff --git a/src/sqlbuild/compiler/compile/models.py b/src/sqlbuild/compiler/compile/models.py index bc9e8571f3..f8fd4c18cd 100644 --- a/src/sqlbuild/compiler/compile/models.py +++ b/src/sqlbuild/compiler/compile/models.py @@ -835,6 +835,7 @@ class CompileProjectInputs: diagnostics: tuple[CompilerDiagnostic, ...] = field(default_factory=tuple) external_sql_reference_resolver: ExternalSqlReferenceResolver | None = None scope_index: ScopeIndex = field(default_factory=ScopeIndex) + declaration_scope: DeclarationScopeBuild | None = field(default=None, repr=False, compare=False) @dataclass(frozen=True) diff --git a/src/sqlbuild/compiler/planner/_helpers/sql_tests/comments.py b/src/sqlbuild/compiler/planner/_helpers/sql_tests/comments.py index 644a5a6a55..21ea2ef363 100644 --- a/src/sqlbuild/compiler/planner/_helpers/sql_tests/comments.py +++ b/src/sqlbuild/compiler/planner/_helpers/sql_tests/comments.py @@ -28,6 +28,8 @@ def uncommented_matches_by_pattern( ) -> tuple[tuple[re.Match[str], ...], ...]: """Find matches for multiple patterns with one protected-region scan.""" + if all(pattern.search(sql) is None for pattern in patterns): + return tuple(() for _pattern in patterns) protected_ranges: tuple[tuple[int, int], ...] = tuple( (match.start(), match.end()) for match in _SQL_NON_CODE_PATTERN.finditer(sql) ) diff --git a/src/sqlbuild/lint/_helpers/expansion.py b/src/sqlbuild/lint/_helpers/expansion.py index c34329f481..72068bc867 100644 --- a/src/sqlbuild/lint/_helpers/expansion.py +++ b/src/sqlbuild/lint/_helpers/expansion.py @@ -19,6 +19,7 @@ from sqlbuild.compiler.compile.main.sql_expansion_context import build_sql_expansion_context from sqlbuild.compiler.compile.models import ( CompiledSqlExpansion, + DeclarationScopeBuild, ExpansionSpan, SqlExpansionContext, ) @@ -85,6 +86,7 @@ def build_lint_expansion_context( project_dir: Path, value_renderer: TypedSqlValueRenderer | None = None, discovered_inputs: DiscoveredProjectInputs | None = None, + declaration_scope: DeclarationScopeBuild | None = None, ) -> SqlExpansionContext: """Build the expansion context, reporting compile failures as lint failures.""" @@ -106,6 +108,7 @@ def build_lint_expansion_context( project_dir=project_dir, discovered_inputs=effective_discovered_inputs, value_renderer=effective_renderer, + declaration_scope=declaration_scope, ) except (AdapterUserError, CompileInputError, DiscoveryError) as error: raise ProjectCompileError( diff --git a/src/sqlbuild/lint/_helpers/project_files.py b/src/sqlbuild/lint/_helpers/project_files.py index 0cd051d8b4..dcbd98fba4 100644 --- a/src/sqlbuild/lint/_helpers/project_files.py +++ b/src/sqlbuild/lint/_helpers/project_files.py @@ -8,10 +8,19 @@ def collect_project_files( - *, project_dir: Path, selected_paths: frozenset[Path] | None = None + *, + project_dir: Path, + selected_paths: frozenset[Path] | None = None, + source_files: dict[Path, str] | None = None, ) -> dict[Path, str]: - """Return all authored SQL files in the project keyed by absolute path.""" - + """Return authored SQL files keyed by path, reusing contents a caller already read.""" + + if source_files is not None: + return { + file_path: contents + for file_path, contents in source_files.items() + if selected_paths is None or file_path.resolve() in selected_paths + } files: dict[Path, str] = {} directory_name: str for directory_name in LINT_DIRECTORY_NAMES: diff --git a/src/sqlbuild/lint/main/build_expansion_context.py b/src/sqlbuild/lint/main/build_expansion_context.py index d01bff6005..de1610fadb 100644 --- a/src/sqlbuild/lint/main/build_expansion_context.py +++ b/src/sqlbuild/lint/main/build_expansion_context.py @@ -2,14 +2,19 @@ from pathlib import Path -from sqlbuild.compiler.compile.models import SqlExpansionContext +from sqlbuild.compiler.compile.models import DeclarationScopeBuild, SqlExpansionContext from sqlbuild.compiler.discovery.models import DiscoveredProjectInputs from sqlbuild.lint._helpers.expansion import build_lint_expansion_context def build_expansion_context( - *, project_dir: Path, discovered_inputs: DiscoveredProjectInputs + *, + project_dir: Path, + discovered_inputs: DiscoveredProjectInputs, + declaration_scope: DeclarationScopeBuild | None = None, ) -> SqlExpansionContext: return build_lint_expansion_context( - project_dir=project_dir, discovered_inputs=discovered_inputs + project_dir=project_dir, + discovered_inputs=discovered_inputs, + declaration_scope=declaration_scope, ) diff --git a/src/sqlbuild/lint/main/run_lint.py b/src/sqlbuild/lint/main/run_lint.py index afcc6c1500..522387c993 100644 --- a/src/sqlbuild/lint/main/run_lint.py +++ b/src/sqlbuild/lint/main/run_lint.py @@ -33,11 +33,12 @@ def run_lint( dynamic_output_paths: frozenset[Path] = frozenset(), compiled_expansions: dict[Path, CompiledSqlExpansion] | None = None, expansion_context: SqlExpansionContext | None = None, + source_files: dict[Path, str] | None = None, ) -> LintRunResult: """Lint all DSL files in the project without modifying anything.""" files: dict[Path, str] = collect_project_files( - project_dir=project_dir, selected_paths=selected_paths + project_dir=project_dir, selected_paths=selected_paths, source_files=source_files ) violations: list[LintViolation] = [] bodies: list[LintBody] = [] diff --git a/src/sqlbuild/rule_engine/_helpers/run/rules.py b/src/sqlbuild/rule_engine/_helpers/run/rules.py index 5b8cdece29..e3496d7b7f 100644 --- a/src/sqlbuild/rule_engine/_helpers/run/rules.py +++ b/src/sqlbuild/rule_engine/_helpers/run/rules.py @@ -19,6 +19,7 @@ CompiledProject, CompiledSqlExpansion, CompileProjectInputs, + DeclarationScopeBuild, SqlExpansionContext, ) from sqlbuild.compiler.compile.types import CompiledResourceType @@ -47,6 +48,7 @@ RulesConfig, RulesResult, RulesRunResult, + SqlExpansionReuse, ) _SQL_RULE_CACHE_VERSION: str = "sql-rules-v2" @@ -70,6 +72,7 @@ def evaluate_rules( dialect: str, selected_keys: frozenset[CompiledObjectKey] | None = None, prepared_sql: PreparedSqlLint | None = None, + expansion_reuse: SqlExpansionReuse | None = None, ) -> RulesRunResult: """Evaluate independent rule phases concurrently, then finalize their combined findings.""" effective_config: RulesConfig = resolve_rule_ignore_selectors( @@ -123,6 +126,7 @@ def evaluate_rules( selected_model_paths=model_paths, cache_enabled=effective_config.cache.enabled, prepared_sql=prepared_sql, + expansion_reuse=expansion_reuse, ) sql_ms: int = round((time.monotonic() - sql_started) * 1000) result: RulesResult = native_result.result() @@ -186,6 +190,7 @@ def prepare_sql_rules( dialect=dialect, enabled_native_rules=codes, header_rules_enabled=False ), discovered_inputs=inputs.discovered_inputs, + declaration_scope=inputs.declaration_scope, compiled_expansions={ model.model_file.file_path: model.sql_expansion for model in inputs.model_inputs @@ -200,10 +205,13 @@ def _prepare_sql_lint( project_dir: Path, config: LintConfig, discovered_inputs: DiscoveredProjectInputs, + declaration_scope: DeclarationScopeBuild | None, compiled_expansions: dict[Path, CompiledSqlExpansion], ) -> PreparedSqlLintResult: context: SqlExpansionContext = build_expansion_context( - project_dir=project_dir, discovered_inputs=discovered_inputs + project_dir=project_dir, + discovered_inputs=discovered_inputs, + declaration_scope=declaration_scope, ) result: LintRunResult = run_lint( project_dir=project_dir, @@ -272,6 +280,8 @@ def _run_prepared_lint( compiled_expansions: dict[Path, CompiledSqlExpansion], dynamic_output_paths: frozenset[Path], prepared_sql: PreparedSqlLint | None, + expansion_reuse: SqlExpansionReuse | None, + source_files: dict[Path, str] | None, ) -> LintRunResult: if prepared_sql is None or set(prepared_sql.codes) != set(config.enabled_native_rules or ()): return run_lint( @@ -281,6 +291,16 @@ def _run_prepared_lint( discovered_inputs=discovered_inputs, compiled_expansions=compiled_expansions, dynamic_output_paths=dynamic_output_paths, + expansion_context=( + _lint_expansion_context( + project_dir=project_dir, + discovered_inputs=discovered_inputs, + expansion_reuse=expansion_reuse, + ) + if config.native_enabled + else None + ), + source_files=source_files, ) completed: PreparedSqlLintResult = prepared_sql.future.result() prepared: LintRunResult = completed.result @@ -314,6 +334,7 @@ def _run_sql_rules( selected_model_paths: frozenset[str] | None, cache_enabled: bool, prepared_sql: PreparedSqlLint | None = None, + expansion_reuse: SqlExpansionReuse | None = None, ) -> _SqlRulesEvaluation: codes: tuple[str, ...] = tuple(rule.code for rule in rules if rule.code.startswith("SQBRSQL")) if not codes: @@ -340,13 +361,13 @@ def _run_sql_rules( findings.extend(cached) selected_paths: set[Path] = {project_dir / path for path in misses} file_identities: dict[str, str] = {} + project_files: dict[Path, str] | None = None if selected_model_paths is None: model_paths: frozenset[Path] = frozenset(project_dir / path for path in models_by_path) + project_files = collect_project_files(project_dir=project_dir, selected_paths=None) file_path: Path contents: str - for file_path, contents in collect_project_files( - project_dir=project_dir, selected_paths=None - ).items(): + for file_path, contents in project_files.items(): if file_path in model_paths: continue relative_path: str = file_path.relative_to(project_dir).as_posix() @@ -385,6 +406,8 @@ def _run_sql_rules( and model.dynamic_column_contract.output_proven ), prepared_sql=prepared_sql, + expansion_reuse=expansion_reuse, + source_files=project_files, ) if selected_paths else None @@ -419,6 +442,26 @@ def _run_sql_rules( ) +def _lint_expansion_context( + *, + project_dir: Path, + discovered_inputs: DiscoveredProjectInputs, + expansion_reuse: SqlExpansionReuse | None, +) -> SqlExpansionContext: + """Build lint expansion, reusing the compiler's scope only for the same discovery.""" + + declaration_scope: DeclarationScopeBuild | None = ( + expansion_reuse.declaration_scope + if expansion_reuse is not None and expansion_reuse.discovered_inputs is discovered_inputs + else None + ) + return build_expansion_context( + project_dir=project_dir, + discovered_inputs=discovered_inputs, + declaration_scope=declaration_scope, + ) + + def _lint_finding(*, violation: LintViolation, project_dir: Path) -> Finding: path: Path = violation.file_path if path.is_absolute() and path.is_relative_to(project_dir.resolve()): diff --git a/src/sqlbuild/rule_engine/classes/early_sql_lint.py b/src/sqlbuild/rule_engine/classes/early_sql_lint.py index 064f91e9a7..e30eb4e87f 100644 --- a/src/sqlbuild/rule_engine/classes/early_sql_lint.py +++ b/src/sqlbuild/rule_engine/classes/early_sql_lint.py @@ -7,13 +7,14 @@ from sqlbuild.compiler.compile.models import CompileProjectInputs from sqlbuild.rule_engine.main._prepare_sql_rules import prepare_sql_rules -from sqlbuild.rule_engine.models import PreparedSqlLint +from sqlbuild.rule_engine.models import PreparedSqlLint, SqlExpansionReuse class EarlySqlLint: def __init__(self, *, enabled: bool) -> None: self.enabled: bool = enabled self.preparation: PreparedSqlLint | None = None + self.expansion_reuse: SqlExpansionReuse | None = None self.executor: ThreadPoolExecutor = ThreadPoolExecutor( max_workers=1, thread_name_prefix="sqlbuild-lint" ) @@ -34,3 +35,11 @@ def start(self, *, inputs: CompileProjectInputs, dialect: str) -> None: self.preparation = prepare_sql_rules( inputs=inputs, executor=self.executor, dialect=dialect ) + self.expansion_reuse = ( + None + if inputs.declaration_scope is None + else SqlExpansionReuse( + discovered_inputs=inputs.discovered_inputs, + declaration_scope=inputs.declaration_scope, + ) + ) diff --git a/src/sqlbuild/rule_engine/main/run_rules.py b/src/sqlbuild/rule_engine/main/run_rules.py index df98639d44..46b7136910 100644 --- a/src/sqlbuild/rule_engine/main/run_rules.py +++ b/src/sqlbuild/rule_engine/main/run_rules.py @@ -6,7 +6,12 @@ from sqlbuild.compiler.discovery.models import DiscoveredProjectInputs from sqlbuild.compiler.pipeline.models import ProjectGraph from sqlbuild.rule_engine._helpers.run.rules import evaluate_rules -from sqlbuild.rule_engine.models import PreparedSqlLint, RulesConfig, RulesRunResult +from sqlbuild.rule_engine.models import ( + PreparedSqlLint, + RulesConfig, + RulesRunResult, + SqlExpansionReuse, +) def run_rules( @@ -18,6 +23,7 @@ def run_rules( dialect: str, selected_keys: frozenset[CompiledObjectKey] | None = None, prepared_sql: PreparedSqlLint | None = None, + expansion_reuse: SqlExpansionReuse | None = None, ) -> RulesRunResult: """Run selected native built-ins before selected custom Python rules.""" @@ -29,4 +35,5 @@ def run_rules( dialect=dialect, selected_keys=selected_keys, prepared_sql=prepared_sql, + expansion_reuse=expansion_reuse, ) diff --git a/src/sqlbuild/rule_engine/models.py b/src/sqlbuild/rule_engine/models.py index 01308ba36b..f5e3519301 100644 --- a/src/sqlbuild/rule_engine/models.py +++ b/src/sqlbuild/rule_engine/models.py @@ -7,7 +7,8 @@ from pathlib import Path from typing import Any -from sqlbuild.compiler.compile.models import SqlExpansionContext +from sqlbuild.compiler.compile.models import DeclarationScopeBuild, SqlExpansionContext +from sqlbuild.compiler.discovery.models import DiscoveredProjectInputs from sqlbuild.lint.models import LintRunResult from sqlbuild.rule_engine.types import RuleCheck, RuleOptionValue, RuleSubject @@ -314,6 +315,14 @@ class PreparedSqlLintResult: context: SqlExpansionContext +@dataclass(frozen=True) +class SqlExpansionReuse: + """Compiler-built declaration scope reusable for SQL checks over the same discovery.""" + + discovered_inputs: DiscoveredProjectInputs + declaration_scope: DeclarationScopeBuild + + @dataclass(frozen=True) class PreparedSqlLint: """Process-local SQL checks started after compiler expansion has completed.""" diff --git a/tests/integration/src/sqlbuild/cli/commands/main/test_rules.py b/tests/integration/src/sqlbuild/cli/commands/main/test_rules.py index 71020110f0..ec9bdab20f 100644 --- a/tests/integration/src/sqlbuild/cli/commands/main/test_rules.py +++ b/tests/integration/src/sqlbuild/cli/commands/main/test_rules.py @@ -3,13 +3,19 @@ from __future__ import annotations import json +from collections.abc import Callable from pathlib import Path from typing import cast import pytest from _pytest.capture import CaptureResult +import sqlbuild.compiler.compile._helpers.attachment.declaration_scope as declaration_scope_module +import sqlbuild.compiler.compile.main._build_compile_inputs as compile_inputs_module +import sqlbuild.compiler.compile.main.sql_expansion_context as expansion_context_module from sqlbuild.cli.commands.main.entrypoint.entry import main +from sqlbuild.compiler.compile.models import DeclarationScopeBuild, LoadedMacro +from sqlbuild.compiler.discovery.models import DiscoveredProjectInputs from tests.integration.src.sqlbuild.cli.commands.main._test_types import ( DynamicPivotRulesIntegrationTestCase, ExplicitContractOutputRuleIntegrationTestCase, @@ -607,6 +613,57 @@ def test_given_cached_sql_test_rules_when_test_or_macro_changes_then_findings_ar assert (tmp_path / "target" / "rules-cache" / "bulk" / "sql.json").is_file() +@pytest.mark.parametrize( + "test_case", + [RulesIntegrationTestCase("warm SQL rules reuse compiler declaration scope", 1, "SQBRSQL004")], + ids=lambda case: case.description, +) +def test_given_warm_scoped_macro_sql_test_when_compiling_then_rules_reuse_compiler_scope( + test_case: RulesIntegrationTestCase, + tmp_path: Path, + capsys: pytest.CaptureFixture[str], + monkeypatch: pytest.MonkeyPatch, +) -> None: + (tmp_path / "sqlbuild_project.toml").write_text( + f'name = "orders"\nadapter = "duckdb"\n\n[rules]\nselect = ["{test_case.expected_code}"]\n', + encoding="utf-8", + ) + model: Path = tmp_path / "models" / "orders.sql" + model.parent.mkdir() + model.write_text('MODEL (description "Orders");\nSELECT 1 AS order_id\n', encoding="utf-8") + tests_dir: Path = tmp_path / "tests" / "unit" + macro: Path = tests_dir / "_macros" / "row_limit.py" + macro.parent.mkdir(parents=True) + macro.write_text('def row_limit() -> str:\n return "LIMIT 1"\n', encoding="utf-8") + (tests_dir / "test_macro_orders.sql").write_text( + "TEST ();\nWITH\n__ref__orders AS (SELECT 1 AS order_id),\n" + "__expected__orders AS (SELECT order_id FROM __ref__orders @row_limit())\n" + "SELECT 1\n", + encoding="utf-8", + ) + macro_finding: str = f"tests/unit/test_macro_orders.sql:{test_case.expected_code}" + cold: set[str] = compile_finding_keys(project_dir=tmp_path, capsys=capsys) + scope_builds: list[Path] = [] + original_build: Callable[..., DeclarationScopeBuild] = ( + declaration_scope_module.build_declaration_scope + ) + + def counting_build( + *, discovered_inputs: DiscoveredProjectInputs, loaded_macros: dict[str, LoadedMacro] + ) -> DeclarationScopeBuild: + scope_builds.append(tmp_path) + return original_build(discovered_inputs=discovered_inputs, loaded_macros=loaded_macros) + + monkeypatch.setattr(compile_inputs_module, "build_declaration_scope", counting_build) + monkeypatch.setattr(expansion_context_module, "build_declaration_scope", counting_build) + + warm: set[str] = compile_finding_keys(project_dir=tmp_path, capsys=capsys) + + assert macro_finding in cold + assert warm == cold + assert len(scope_builds) == 1 + + @pytest.mark.parametrize( "test_case", [RulesIntegrationTestCase("custom rule is enforced and cached", 1, "XSQBRARCH001")], From e7e1161851020d4f43a12085cfba9f8c9f6475b8 Mon Sep 17 00:00:00 2001 From: Kevin Longe <273747162+kvlonge@users.noreply.github.com> Date: Wed, 23 Sep 2026 10:55:41 +0100 Subject: [PATCH 2/2] fix: keep background SQL lint on private macro instances --- src/sqlbuild/rule_engine/_helpers/run/rules.py | 6 +----- src/sqlbuild/rule_engine/models.py | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/sqlbuild/rule_engine/_helpers/run/rules.py b/src/sqlbuild/rule_engine/_helpers/run/rules.py index e3496d7b7f..3979bca495 100644 --- a/src/sqlbuild/rule_engine/_helpers/run/rules.py +++ b/src/sqlbuild/rule_engine/_helpers/run/rules.py @@ -190,7 +190,6 @@ def prepare_sql_rules( dialect=dialect, enabled_native_rules=codes, header_rules_enabled=False ), discovered_inputs=inputs.discovered_inputs, - declaration_scope=inputs.declaration_scope, compiled_expansions={ model.model_file.file_path: model.sql_expansion for model in inputs.model_inputs @@ -205,13 +204,10 @@ def _prepare_sql_lint( project_dir: Path, config: LintConfig, discovered_inputs: DiscoveredProjectInputs, - declaration_scope: DeclarationScopeBuild | None, compiled_expansions: dict[Path, CompiledSqlExpansion], ) -> PreparedSqlLintResult: context: SqlExpansionContext = build_expansion_context( - project_dir=project_dir, - discovered_inputs=discovered_inputs, - declaration_scope=declaration_scope, + project_dir=project_dir, discovered_inputs=discovered_inputs ) result: LintRunResult = run_lint( project_dir=project_dir, diff --git a/src/sqlbuild/rule_engine/models.py b/src/sqlbuild/rule_engine/models.py index f5e3519301..f5f7df34b0 100644 --- a/src/sqlbuild/rule_engine/models.py +++ b/src/sqlbuild/rule_engine/models.py @@ -317,7 +317,7 @@ class PreparedSqlLintResult: @dataclass(frozen=True) class SqlExpansionReuse: - """Compiler-built declaration scope reusable for SQL checks over the same discovery.""" + """Compiler declaration scope for post-assembly SQL checks; assembly still runs its macros.""" discovered_inputs: DiscoveredProjectInputs declaration_scope: DeclarationScopeBuild