import pathlib from functools import partial from typing import Any, Callable, Dict, Optional, Sequence, Tuple, Type, Union __all__ = ( "Types", "SYSTEMD_SERVICE_CONFIG", "SYSTEMD_NETWORK_CONFIG", "SYSTEMD_CONFIG_ROOT", ) SYSTEMD_CONFIG_ROOT = pathlib.Path("/etc/systemd") SYSTEMD_NETWORK_CONFIG = SYSTEMD_CONFIG_ROOT / "network" SYSTEMD_SERVICE_CONFIG = SYSTEMD_CONFIG_ROOT / "system" class _sdict(dict): _help: Optional[str] __name__: str class _Type(type): def __new__(metacls, cls, bases, classdict, **kwds): individual = dict() virtfunc = None virtual = () special = dict() for key, value in classdict.items(): if key.startswith("_"): if key == "__getattr__": virtfunc = value special[key] = value elif key == "__dir__": virtual = tuple(value(None)) special[key] = value elif key in ("__doc__", "__module__", "__qualname__"): special[key] = value else: individual[key] = value if len(virtual) != 0 and virtfunc is None: # pragma: nocover raise TypeError("Virtual funcs defined, but no func to generate them defined") special["_attr"] = tuple(virtual + tuple(individual.keys())) special["_vfunc"] = virtfunc special["_virtual"] = virtual special["_individual"] = individual annotations = dict() if len(virtual) != 0 and virtfunc is not None: # pragma: nocover anno = virtfunc(None, virtual[0]).__annotations__ for virtualkey in virtual: annotations[virtualkey] = Callable[[*anno.values()], Dict[str, Any]] annotations["__dir__"] = Callable[[], Tuple[str]] special["__annotations__"] = annotations inst = super().__new__(metacls, cls, bases, special, **kwds) return inst def __getattribute__(self, __name: str) -> Any: if __name in ( "__dict__", "__doc__", "_attr", "__annotations__", "_virtual", "_vfunc", "_individual", ): return super().__getattribute__(__name) if __name in self._virtual: return self._vfunc(self, __name) if __name in self._individual: return partial(self._individual[__name], self) return super().__getattribute__(__name) def __dir__(self): data = set() data.update(("__dir__", "__doc__", "__annotations__")) data.update(self._virtual) data.update(self._individual.keys()) return tuple(data) class Types(metaclass=_Type): """Provides helpers for the ansible types""" @staticmethod def list( self, elements: Union[Type[object], str], required: bool = False, help: Optional[str] = None, ) -> dict: if not isinstance(elements, str): elements = elements.__name__ option = _sdict(type="list", elements=elements, required=required) option._help = help return option def __dir__(self) -> tuple: return ( "str", "dict", "bool", "int", "float", "path", "raw", "jsonarg", "json", "bytes", "bits", ) def __getattr__(self, name: str): def argument( required: bool = False, help: Optional[str] = None, choices: Optional[Sequence] = None, default: Optional[Any] = None, ): """Simple wrapper for Ansible {0} argument dict""" output = _sdict(type=name, required=required) if choices is not None: output["choices"] = choices if default is not None: output["default"] = default output._help = help return output argument.__name__ = name argument.__doc__ = argument.__doc__.format(name) return argument