import importlib def _load(kind: str, name: str, config, *args): if not name or not name.replace("_", "").replace("-", "").isalnum(): raise RuntimeError(f"Invalid {kind} plugin name: {name!r}") module_name = name.replace("-", "_") path = f"dns_sync.plugins.{kind}.{module_name}" try: module = importlib.import_module(path) except ModuleNotFoundError as exc: if exc.name == path: raise RuntimeError(f"Unknown {kind[:-1]} plugin: {name}") from exc raise plugin_class = getattr(module, "Plugin", None) if plugin_class is None: raise RuntimeError(f"Plugin module {path} does not export Plugin") return plugin_class(config, *args) def load_source(name: str, config): return _load("sources", name, config) def load_provider(name: str, config): return _load("providers", name, config) def load_adapter(name: str, config, endpoint): return _load("adapters", name, config, endpoint)