from typing import List, Optional, Dict, Tuple from pathlib import Path class Config: def merge_with(self, other, strict: bool = False): """ Merges the other config into this one :param other: :param strict: whether conflicting options are allowed or not :return: self """ for var in vars(self): if not getattr(self, var): setattr(self, var, getattr(other, var)) else: if strict and getattr(other, var) is not None and getattr(self, var) != getattr(other, var): raise NotImplementedError return self class FormatterIF: """ A formatter is bound to a specific input file with some building configuration. """ def __init__( self, input_file: Optional[Path] = None, config: Optional[Config] = None, ): self._input_file: Optional[Path] = input_file self._config: Optional[Config] = config def format(self, build_dir: Path, overwrite: bool = False) -> Optional[List[Tuple[str, Dict]]]: """ :param build_dir: Directory where output files are written to :param overwrite: overwrite existing files :return: When configuration files are needed for a future build of the output files, a list of the file names and their needed configurations. Else None. """ raise NotImplementedError @property def output_files(self) -> List[str]: """ :return: List of files that will be built when the formatter is invoked """ raise NotImplementedError @property def input_file(self) -> Path: if self._input_file is None: raise NotImplementedError return self._input_file @input_file.setter def input_file(self, input_file: Path) -> None: self._input_file = input_file @property def config(self) -> Config: if self._config is None: raise NotImplementedError return self._config @config.setter def config(self, config: Config): self._config = config