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

1"""Preset registry for built-in validation configuration presets. 

2 

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. 

6 

7Key types: 

8- PresetRegistry: Class with get(), list_presets() methods for preset access 

9""" 

10 

11from __future__ import annotations 

12 

13from importlib import resources 

14from typing import TYPE_CHECKING, Any, ClassVar 

15 

16import yaml 

17 

18from src.domain.validation.config import PresetNotFoundError 

19from src.domain.validation.config_loader import _build_config 

20 

21if TYPE_CHECKING: 

22 from src.domain.validation.config import ValidationConfig 

23 

24 

25class PresetRegistry: 

26 """Registry for built-in validation configuration presets. 

27 

28 Presets are YAML files stored in the src/domain/validation/presets/ package 

29 and discovered via importlib.resources for wheel compatibility. 

30 

31 Example: 

32 >>> registry = PresetRegistry() 

33 >>> config = registry.get("python-uv") 

34 >>> print(config.commands.test.command) 

35 'uv run pytest' 

36 """ 

37 

38 # Package containing preset YAML files 

39 _PRESETS_PACKAGE: ClassVar[str] = "src.domain.validation.presets" 

40 

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 } 

48 

49 def get(self, name: str) -> ValidationConfig: 

50 """Load and return a preset configuration by name. 

51 

52 Args: 

53 name: Name of the preset (e.g., "python-uv", "go"). 

54 

55 Returns: 

56 ValidationConfig instance with preset values. 

57 

58 Raises: 

59 PresetNotFoundError: If the preset name is not recognized. 

60 

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()) 

69 

70 data = self._load_preset_yaml(name) 

71 return _build_config(data) 

72 

73 def list_presets(self) -> list[str]: 

74 """Return a sorted list of available preset names. 

75 

76 Returns: 

77 List of preset names in alphabetical order. 

78 

79 Example: 

80 >>> registry = PresetRegistry() 

81 >>> registry.list_presets() 

82 ['go', 'node-npm', 'python-uv', 'rust'] 

83 """ 

84 return sorted(self._PRESET_FILES.keys()) 

85 

86 def _load_preset_yaml(self, name: str) -> dict[str, Any]: 

87 """Load and parse a preset YAML file. 

88 

89 Args: 

90 name: Name of the preset. 

91 

92 Returns: 

93 Parsed YAML dictionary. 

94 

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