import tomllib from dataclasses import dataclass from pathlib import Path from typing import Iterable from ..util import merge_dicts from .model import Preset @dataclass class PresetLoaderConfig: default: bool = True user: bool = True project: bool = True class PresetLoader: _source_cache: dict[Path, dict] = {} def __init__(self, basepath: Path, config: PresetLoaderConfig | None = None): self._basepath = basepath self._config = config or PresetLoaderConfig() def _iter_sources(self) -> Iterable[Path]: if self._config.default: yield from (Path(__file__).parent / "default").iterdir() if self._config.user: user_preset = Path.home() / ".pm.toml" if user_preset.exists(): yield user_preset if self._config.project: projectpath = self._basepath while projectpath.exists(): project_preset = projectpath / ".pm.toml" if project_preset.exists(): yield project_preset if projectpath.parent == projectpath: break projectpath = projectpath.parent def load(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] = tomllib.load(fd) merge_dicts(result_preset_data, self._source_cache[filepath]) return Preset(**result_preset_data)