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