Implementing a plug-in mechanism

Weatherby,Gerard gweatherby at uchc.edu
Wed Mar 15 18:06:18 EDT 2023


I do something similar to Thomas. (Also MIT licensed). I like objects. I like type hints.

Each plugin needs to have check and purpose functions and accepts either PluginSpec (by default) or AddonSpec if it defines addon = True

This requires a single-level plugin directory with no extra files in it (unless they start with _, like __init__.py)


And I should use os.path.splitext but I forget what’s it called and find it easier just to split.

# noinspection PyUnresolvedReferences
@dataclass
class NamedModule:
    """Datacheck module and its name"""
    mod: object
    name: str

    def __post_init__(self):
        """Validate attributes"""
        assert hasattr(self.mod, 'check')
        assert hasattr(self.mod, 'purpose')

    def check(self, inspec: Union[PluginSpec, AddonSpec]) -> PluginResult:
        return self.mod.check(inspec)

    @property
    def purpose(self) -> str:
        return self.mod.purpose()

    @property
    def addon(self) -> bool:
        """Return true if this module uses AddonSpec"""
        return getattr(self.mod, 'addon', False)


class Integrity:

   @property
    def plugins(self) -> List[NamedModule]:
        """Get list of plugins by scanning plugin directory"""
        modules = []
        us = os.path.abspath(__file__)
        plugin_dir = os.path.join(os.path.dirname(us), 'plugins')
        de: os.DirEntry
        for de in os.scandir(plugin_dir):
            if not de.name.startswith('_'):
                n = de.name.split('.')[0]
                mod = importlib.import_module(f'.plugins.{n}', 'dataintegrity')
                modules.append(NamedModule(mod, n))
        return modules


More information about the Python-list mailing list