""" Part of the tagit module. A copy of the license is provided with the project. Author: Matthias Baumgartner, 2022 """ # standard imports from collections import abc from functools import partial from inspect import isclass import typing # exports __all__: typing.Sequence[str] = ( 'BuilderBase', 'InvalidFactoryName', ) ## code ## class InvalidFactoryName(KeyError): pass class BuilderBase(abc.Mapping, abc.Hashable): _factories = dict() def __getitem__(self, key): return self.get(key) def __contains__(self, key): return key in self._factories def __iter__(self): return iter(self._factories.keys()) def __hash__(self): return hash(frozenset(self._factories.items())) def __len__(self): return len(self._factories) def __eq__(self, other): return type(self) == type(other) and self._factories == other._factories def get(self, key): if key not in self._factories: raise InvalidFactoryName(key) return self._factories[key] @classmethod def keys(self): return self._factories.keys() @classmethod def items(self): return self._factories.items() @classmethod def describe(cls, key): if key not in cls._factories: raise InvalidFactoryName(key) desc = cls._factories[key].__doc__ return desc if desc is not None else '' def prepare(self, key, *args, **kwargs): # If building is to be customized, overwrite this function. return partial(self[key], *args, **kwargs) def build(self, key, *args, **kwargs): fu = self.prepare(key, *args, **kwargs) return fu() def key_from_instance(self, cls): for key, clbk in self._factories.items(): if isclass(clbk) and isinstance(cls, clbk): return key if not isclass(clbk) and cls == clbk: return key raise KeyError(type(cls)) ## EOF ##