Coverage for src / domain / validation / preset_registry.py: 100%
26 statements
« prev ^ index » next coverage.py v7.13.0, created at 2026-01-04 04:43 +0000
« prev ^ index » next coverage.py v7.13.0, created at 2026-01-04 04:43 +0000
1"""Preset registry for built-in validation configuration presets.
3This module provides the PresetRegistry class for loading and managing built-in
4validation configuration presets. Presets are YAML files bundled with the package
5and discovered via importlib.resources.
7Key types:
8- PresetRegistry: Class with get(), list_presets() methods for preset access
9"""
11from __future__ import annotations
13from importlib import resources
14from typing import TYPE_CHECKING, Any, ClassVar
16import yaml
18from src.domain.validation.config import PresetNotFoundError
19from src.domain.validation.config_loader import _build_config
21if TYPE_CHECKING:
22 from src.domain.validation.config import ValidationConfig
25class PresetRegistry:
26 """Registry for built-in validation configuration presets.
28 Presets are YAML files stored in the src/domain/validation/presets/ package
29 and discovered via importlib.resources for wheel compatibility.
31 Example:
32 >>> registry = PresetRegistry()
33 >>> config = registry.get("python-uv")
34 >>> print(config.commands.test.command)
35 'uv run pytest'
36 """
38 # Package containing preset YAML files
39 _PRESETS_PACKAGE: ClassVar[str] = "src.domain.validation.presets"
41 # Mapping of preset names to YAML filenames
42 _PRESET_FILES: ClassVar[dict[str, str]] = {
43 "go": "go.yaml",
44 "node-npm": "node-npm.yaml",
45 "python-uv": "python-uv.yaml",
46 "rust": "rust.yaml",
47 }
49 def get(self, name: str) -> ValidationConfig:
50 """Load and return a preset configuration by name.
52 Args:
53 name: Name of the preset (e.g., "python-uv", "go").
55 Returns:
56 ValidationConfig instance with preset values.
58 Raises:
59 PresetNotFoundError: If the preset name is not recognized.
61 Example:
62 >>> registry = PresetRegistry()
63 >>> config = registry.get("go")
64 >>> print(config.commands.test.command)
65 'go test ./...'
66 """
67 if name not in self._PRESET_FILES:
68 raise PresetNotFoundError(name, self.list_presets())
70 data = self._load_preset_yaml(name)
71 return _build_config(data)
73 def list_presets(self) -> list[str]:
74 """Return a sorted list of available preset names.
76 Returns:
77 List of preset names in alphabetical order.
79 Example:
80 >>> registry = PresetRegistry()
81 >>> registry.list_presets()
82 ['go', 'node-npm', 'python-uv', 'rust']
83 """
84 return sorted(self._PRESET_FILES.keys())
86 def _load_preset_yaml(self, name: str) -> dict[str, Any]:
87 """Load and parse a preset YAML file.
89 Args:
90 name: Name of the preset.
92 Returns:
93 Parsed YAML dictionary.
95 Raises:
96 PresetNotFoundError: If the preset file cannot be loaded.
97 """
98 filename = self._PRESET_FILES[name]
99 try:
100 package_files = resources.files(self._PRESETS_PACKAGE)
101 preset_file = package_files.joinpath(filename)
102 content = preset_file.read_text(encoding="utf-8")
103 data = yaml.safe_load(content)
104 return data if data is not None else {}
105 except (ModuleNotFoundError, FileNotFoundError, TypeError) as e:
106 raise PresetNotFoundError(name, self.list_presets()) from e