Source code for nlp_shap.plugins.registry

"""Plugin registry with entry-point discovery."""

from __future__ import annotations

from collections.abc import Callable
from importlib.metadata import entry_points
from typing import cast

from .groups import PluginGroup

PluginFactory = Callable[[], object]
"""Callable that materializes a plugin instance."""


[docs] class PluginRegistry: """Register and resolve pipeline plugins by group and name.""" def __init__(self) -> None: self._factories: dict[str, dict[str, PluginFactory]] = {}
[docs] def register( self, group: PluginGroup | str, name: str, factory: PluginFactory, ) -> None: """Register a plugin factory under ``group`` and ``name``.""" group_key = str(group) factories = self._factories.setdefault(group_key, {}) factories[name] = factory
[docs] def resolve(self, group: PluginGroup | str, name: str) -> object: """Instantiate a plugin registered under ``group`` and ``name``.""" group_key = str(group) try: factory = self._factories[group_key][name] except KeyError as error: msg = f"unknown plugin {name!r} in group {group_key!r}" raise LookupError(msg) from error return factory()
[docs] def names(self, group: PluginGroup | str) -> tuple[str, ...]: """Return sorted plugin names registered for ``group``.""" group_key = str(group) return tuple(sorted(self._factories.get(group_key, {})))
[docs] def load_entry_points(self, group: PluginGroup | str) -> None: """Discover and register plugins from a packaging entry-point group.""" group_key = str(group) discovered = entry_points(group=group_key) for entry_point in discovered: target = entry_point.load() if isinstance(target, type): factory: PluginFactory = target else: factory = cast(PluginFactory, target) self.register(group_key, entry_point.name, factory)