From c3e99c7c523f00c56aa8ade6d7646318c86b40b5 Mon Sep 17 00:00:00 2001 From: Kevin Longe <273747162+kvlonge@users.noreply.github.com> Date: Sun, 4 Oct 2026 15:43:08 +0100 Subject: [PATCH] perf(compile): keep command models out of the compile import path Command-group warehouse selection imported its three small dataclasses from the CLI command models module, which pulls in every command's request and result models. Every command, including warm compiles, paid that import. Move the warehouse scope models beside the CLI entry models and guard the compile import footprint with a fresh-process test. --- .../_helpers/build_execution/run_context.py | 3 +- .../cli/commands/_helpers/debug/checks.py | 7 +-- .../commands/_helpers/runtime/warehouses.py | 4 +- src/sqlbuild/cli/commands/models.py | 32 ----------- src/sqlbuild/cli/entry/models.py | 34 ++++++++++- .../_helpers/runtime/test_warehouses.py | 2 +- .../cli/commands/main/compile/_test_types.py | 8 +++ .../compile/test_compile_import_footprint.py | 57 +++++++++++++++++++ 8 files changed, 106 insertions(+), 41 deletions(-) create mode 100644 tests/unit/src/sqlbuild/cli/commands/main/compile/test_compile_import_footprint.py diff --git a/src/sqlbuild/cli/commands/_helpers/build_execution/run_context.py b/src/sqlbuild/cli/commands/_helpers/build_execution/run_context.py index 77a4f2975c..e9912e3533 100644 --- a/src/sqlbuild/cli/commands/_helpers/build_execution/run_context.py +++ b/src/sqlbuild/cli/commands/_helpers/build_execution/run_context.py @@ -12,7 +12,8 @@ C1_CONTROL_CODE_LIMIT, C1_CONTROL_CODE_START, ) -from sqlbuild.cli.commands.models import BuildRunContext, ResolvedWarehouse +from sqlbuild.cli.commands.models import BuildRunContext +from sqlbuild.cli.entry.models import ResolvedWarehouse from sqlbuild.presentation.classes.cli_document import CliDocument from sqlbuild.presentation.classes.cli_style import CliStyle diff --git a/src/sqlbuild/cli/commands/_helpers/debug/checks.py b/src/sqlbuild/cli/commands/_helpers/debug/checks.py index fe78f4c85e..36e6e294d0 100644 --- a/src/sqlbuild/cli/commands/_helpers/debug/checks.py +++ b/src/sqlbuild/cli/commands/_helpers/debug/checks.py @@ -20,14 +20,13 @@ resolve_command_warehouse, ) from sqlbuild.cli.commands.exceptions import CliUserError -from sqlbuild.cli.commands.models import ( +from sqlbuild.cli.commands.models import DebugLine, DebugResult +from sqlbuild.cli.commands.types import DebugCheckStatus +from sqlbuild.cli.entry.models import ( AuthoredTargetWarehouse, CommandWarehouseScope, - DebugLine, - DebugResult, ResolvedWarehouse, ) -from sqlbuild.cli.commands.types import DebugCheckStatus from sqlbuild.compiler.compile.exceptions import CompileInputError from sqlbuild.compiler.compile.main.effective_target_namespace import ( build_effective_target_namespace, diff --git a/src/sqlbuild/cli/commands/_helpers/runtime/warehouses.py b/src/sqlbuild/cli/commands/_helpers/runtime/warehouses.py index 174f146c58..f2d21c241c 100644 --- a/src/sqlbuild/cli/commands/_helpers/runtime/warehouses.py +++ b/src/sqlbuild/cli/commands/_helpers/runtime/warehouses.py @@ -18,12 +18,12 @@ CONNECTION_WAREHOUSE_SOURCE, ) from sqlbuild.cli.commands.exceptions import CliUserError -from sqlbuild.cli.commands.models import ( +from sqlbuild.cli.commands.types import CliCommand +from sqlbuild.cli.entry.models import ( AuthoredTargetWarehouse, CommandWarehouseScope, ResolvedWarehouse, ) -from sqlbuild.cli.commands.types import CliCommand from sqlbuild.compiler.compile.exceptions import CompileInputError from sqlbuild.compiler.compile.main.effective_runtime import build_effective_runtime_config from sqlbuild.compiler.compile.main.expand_template_data import expand_template_data diff --git a/src/sqlbuild/cli/commands/models.py b/src/sqlbuild/cli/commands/models.py index 7d222bcb26..906928cc66 100644 --- a/src/sqlbuild/cli/commands/models.py +++ b/src/sqlbuild/cli/commands/models.py @@ -89,38 +89,6 @@ SnapshotsConfig, SourceEntry, ) -from sqlbuild.spec.contracts.types import WarehouseGroup - - -@dataclass(frozen=True) -class CommandWarehouseScope: - """The warehouse group and CLI override active for one command invocation.""" - - group: WarehouseGroup | None - cli_warehouse: str | None = None - cli_vars: dict[str, object] = field(default_factory=dict) - - -@dataclass(frozen=True) -class AuthoredTargetWarehouse: - """One target's authored, unexpanded warehouse for a command group and its file.""" - - warehouse: str - target_name: str - group: WarehouseGroup - file_name: str - - @property - def source(self) -> str: - return f"{self.file_name} [targets.{self.target_name}.warehouses] {self.group.value}" - - -@dataclass(frozen=True) -class ResolvedWarehouse: - """The warehouse one command connects with and where that value came from.""" - - warehouse: str | None - source: str @dataclass(frozen=True) diff --git a/src/sqlbuild/cli/entry/models.py b/src/sqlbuild/cli/entry/models.py index 371fafc465..dbd83d921d 100644 --- a/src/sqlbuild/cli/entry/models.py +++ b/src/sqlbuild/cli/entry/models.py @@ -3,7 +3,7 @@ from __future__ import annotations from collections.abc import Callable -from dataclasses import dataclass +from dataclasses import dataclass, field from pathlib import Path from sqlbuild.cli.commands.classes.cli_namespace import CliNamespace @@ -17,6 +17,7 @@ SkillsUpdateCommandHandler, ) from sqlbuild.cli.compile.models import CompileCommandRequest +from sqlbuild.spec.contracts.types import WarehouseGroup @dataclass(frozen=True) @@ -79,3 +80,34 @@ class CliEntrypointHandlers: run_scope: ScopeCommandHandler run_contract: Callable[..., int] | None = None run_refactor: Callable[..., int] | None = None + + +@dataclass(frozen=True) +class CommandWarehouseScope: + """The warehouse group and CLI override active for one command invocation.""" + + group: WarehouseGroup | None + cli_warehouse: str | None = None + cli_vars: dict[str, object] = field(default_factory=dict) + + +@dataclass(frozen=True) +class AuthoredTargetWarehouse: + """One target's authored, unexpanded warehouse for a command group and its file.""" + + warehouse: str + target_name: str + group: WarehouseGroup + file_name: str + + @property + def source(self) -> str: + return f"{self.file_name} [targets.{self.target_name}.warehouses] {self.group.value}" + + +@dataclass(frozen=True) +class ResolvedWarehouse: + """The warehouse one command connects with and where that value came from.""" + + warehouse: str | None + source: str diff --git a/tests/unit/src/sqlbuild/cli/commands/_helpers/runtime/test_warehouses.py b/tests/unit/src/sqlbuild/cli/commands/_helpers/runtime/test_warehouses.py index 6bcddd2371..945ccd3bff 100644 --- a/tests/unit/src/sqlbuild/cli/commands/_helpers/runtime/test_warehouses.py +++ b/tests/unit/src/sqlbuild/cli/commands/_helpers/runtime/test_warehouses.py @@ -15,8 +15,8 @@ ) from sqlbuild.cli.commands.constants import COMMAND_WAREHOUSE_GROUPS from sqlbuild.cli.commands.exceptions import CliUserError -from sqlbuild.cli.commands.models import ResolvedWarehouse from sqlbuild.cli.commands.types import CliCommand +from sqlbuild.cli.entry.models import ResolvedWarehouse from sqlbuild.compiler.discovery.models import DiscoveredProjectInputs from sqlbuild.spec.contracts.models import LocalTargetConfig, TargetWarehousesConfig from sqlbuild.spec.contracts.types import WarehouseGroup diff --git a/tests/unit/src/sqlbuild/cli/commands/main/compile/_test_types.py b/tests/unit/src/sqlbuild/cli/commands/main/compile/_test_types.py index 2dc1abf35d..2512e7ec3c 100644 --- a/tests/unit/src/sqlbuild/cli/commands/main/compile/_test_types.py +++ b/tests/unit/src/sqlbuild/cli/commands/main/compile/_test_types.py @@ -197,3 +197,11 @@ class CompileCyclicCollectionTestCase: collection_enabled_before: bool expected_enabled_during: bool expected_enabled_after: bool + + +@dataclass(frozen=True) +class CompileImportFootprintTestCase: + description: str + checked_modules: tuple[str, ...] + expected_exit_code: int + expected_loaded_modules: tuple[str, ...] diff --git a/tests/unit/src/sqlbuild/cli/commands/main/compile/test_compile_import_footprint.py b/tests/unit/src/sqlbuild/cli/commands/main/compile/test_compile_import_footprint.py new file mode 100644 index 0000000000..23406d5953 --- /dev/null +++ b/tests/unit/src/sqlbuild/cli/commands/main/compile/test_compile_import_footprint.py @@ -0,0 +1,57 @@ +"""Compile command import footprint in a fresh interpreter.""" + +from __future__ import annotations + +import json +import subprocess +import sys +from pathlib import Path +from typing import cast + +import pytest + +from tests.unit.src.sqlbuild.cli.commands.main.compile._test_types import ( + CompileImportFootprintTestCase, +) +from tests.unit.src.sqlbuild.cli.commands.main.compile.helpers import ( + prepare_static_compile_project, +) + + +@pytest.mark.parametrize( + "test_case", + [ + CompileImportFootprintTestCase( + description="compile skips build and execution command models", + checked_modules=( + "sqlbuild.cli.commands.models", + "sqlbuild.executor.build.models", + "sqlbuild.executor.run.models", + ), + expected_exit_code=0, + expected_loaded_modules=(), + ) + ], + ids=lambda case: case.description, +) +def test_given_local_project_when_compiling_in_fresh_process_then_command_models_stay_unloaded( + test_case: CompileImportFootprintTestCase, tmp_path: Path +) -> None: + project_dir: Path = prepare_static_compile_project(tmp_path) + script: str = ( + "import contextlib, io, json, sys\n" + "from sqlbuild.cli.entry.main.entry import main\n" + "with contextlib.redirect_stdout(io.StringIO()):\n" + f" code = main(['--project-dir', {str(project_dir)!r}, 'compile', '--json'])\n" + f"names = {test_case.checked_modules!r}\n" + "print(json.dumps({'code': code, " + "'loaded': [name for name in names if name in sys.modules]}))\n" + ) + + result: subprocess.CompletedProcess[str] = subprocess.run( + [sys.executable, "-c", script], check=True, capture_output=True, text=True + ) + outcome: dict[str, object] = json.loads(result.stdout.strip().splitlines()[-1]) + + assert outcome["code"] == test_case.expected_exit_code + assert tuple(cast(list[str], outcome["loaded"])) == test_case.expected_loaded_modules