Let adapter plugins provide configured endpoints

This commit is contained in:
Lyncoln
2026-09-20 19:20:26 -04:00
parent 832928159d
commit 16359dc164
6 changed files with 421 additions and 34 deletions
+99 -22
View File
@@ -89,7 +89,29 @@ def _load_external_adapter_module(name: str):
existing = sys.modules.get(qualified_name)
if existing is not None:
return existing
existing_file = getattr(
existing,
"__file__",
None,
)
if existing_file is not None:
try:
same_file = (
Path(existing_file).resolve()
== package_path.resolve()
)
except OSError:
same_file = False
else:
same_file = False
if same_file:
return existing
# The same plugin name is being resolved from a different
# external plugin root. Do not reuse stale module state.
sys.modules.pop(qualified_name, None)
spec = importlib.util.spec_from_file_location(
qualified_name,
@@ -129,6 +151,72 @@ def _load_builtin(kind: str, name: str):
raise
def _adapter_module(name: str):
normalized = _validate_plugin_name("adapter", name)
enabled = enabled_plugins()
if normalized not in enabled:
raise RuntimeError(
f"Adapter plugin {normalized!r} is not enabled"
)
module = _load_builtin("adapters", normalized)
if module is not None:
return (
normalized,
module,
f"dns_sync.plugins.adapters.{normalized}",
)
module = _load_external_adapter_module(normalized)
if module is not None:
return (
normalized,
module,
str(
_external_plugin_root()
/ normalized
/ "__init__.py"
),
)
raise RuntimeError(
f"Unknown adapter plugin: {normalized}"
)
def configured_adapter_endpoints(
name: str,
config,
):
normalized, module, display_path = _adapter_module(name)
loader = getattr(
module,
"configured_endpoints",
None,
)
if loader is None:
raise RuntimeError(
f"Adapter plugin {display_path} does not export "
"configured_endpoints"
)
endpoints = tuple(loader(config))
for endpoint in endpoints:
if endpoint.plugin != normalized:
raise RuntimeError(
f"Adapter plugin {normalized!r} returned endpoint "
f"for plugin {endpoint.plugin!r}"
)
return endpoints
def _plugin_class(module, display_path: str):
plugin_class = getattr(module, "Plugin", None)
@@ -144,12 +232,17 @@ def _load(kind: str, name: str, config, *args):
normalized = _validate_plugin_name(kind, name)
if kind == "adapters":
enabled = enabled_plugins()
(
normalized,
module,
display_path,
) = _adapter_module(normalized)
if normalized not in enabled:
raise RuntimeError(
f"Adapter plugin {normalized!r} is not enabled"
)
plugin_class = _plugin_class(
module,
display_path,
)
return plugin_class(config, *args)
module = _load_builtin(kind, normalized)
@@ -160,22 +253,6 @@ def _load(kind: str, name: str, config, *args):
)
return plugin_class(config, *args)
if kind == "adapters":
module = _load_external_adapter_module(
normalized
)
if module is not None:
plugin_class = _plugin_class(
module,
str(
_external_plugin_root()
/ normalized
/ "__init__.py"
),
)
return plugin_class(config, *args)
raise RuntimeError(
f"Unknown {kind[:-1]} plugin: {normalized}"
)