import dataclasses from typing import List from dbt.clients.system import write_json def list_str() -> List[str]: """Mypy gets upset about stuff like: from dataclasses import dataclass, field from typing import Optional, List @dataclass class Foo: x: Optional[List[str]] = field(default_factory=list) Because `list` could be any kind of list, I guess """ return [] class Replaceable: def replace(self, **kwargs): return dataclasses.replace(self, **kwargs) class Mergeable(Replaceable): def merged(self, *args): """Perform a shallow merge, where the last non-None write wins. This is intended to merge dataclasses that are a collection of optional values. """ replacements = {} cls = type(self) for arg in args: for field in dataclasses.fields(cls): value = getattr(arg, field.name) if value is not None: replacements[field.name] = value return self.replace(**replacements) class Writable: def write(self, path: str, omit_none: bool = False): write_json(path, self.to_dict(omit_none=omit_none)) # type: ignore