from dataclasses import dataclass from pathlib import Path from typing import Dict, Iterable, Optional import tomli from ..util import merge_dicts from .model import Preset __all__ = ( "PresetResolverConfig", "PresetResolver", ) @dataclass class PresetResolverConfig: default: bool = True user: bool = True project: bool = True class PresetResolver: _source_cache: Dict[Path, dict] = {} def __init__(self, basepath: Path, config: Optional[PresetResolverConfig] = None): self._basepath = basepath self._config = config or PresetResolverConfig() def iter_sources(self) -> Iterable[Path]: if self._config.default: for filepath in (Path(__file__).parent / "default").iterdir(): yield filepath if self._config.user: user_preset = Path.home() / ".preset.toml" if user_preset.exists(): yield user_preset if self._config.project: projectpath = self._basepath while projectpath.exists(): project_preset = projectpath / ".preset.toml" if project_preset.exists(): yield project_preset if projectpath.parent == projectpath: break projectpath = projectpath.parent def resolve_preset(self) -> Preset: result_preset_data = {} for filepath in self.iter_sources(): if filepath not in self._source_cache: with open(filepath, "rb") as fd: self._source_cache[filepath] = tomli.load(fd) merge_dicts(result_preset_data, self._source_cache[filepath]) return Preset(**result_preset_data)