Let adapter plugins provide configured endpoints
This commit is contained in:
+99
-22
@@ -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}"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user