Source code for core.plugin

"""
This module contains functionality for configurable plugins.
"""

import abc
import importlib
import typing
import pathlib

from django.conf import settings


[docs]class Plugin(abc.ABCMeta): """ Metaclass for plugin components. The base class for each type of plugin should use this metaclass. """ def __init__(cls, name, bases, attrs): """ Metaclass initialiser - called when a new class is defined. When a new class is defined it will be registered as an available plugin. :param name: Name of the new class :param bases: Base classes of the new class :param attrs: Attributes of the new class """ super().__init__(name, bases, attrs) if not hasattr(cls, '_plugins'): cls._plugins = {} else: cls._plugins[name] = cls
[docs] def get_plugin(cls, class_name: str) -> typing.Type: """ Get a plugin class by name. :param class_name: Name of plugin class :return: Plugin class """ return cls._plugins[class_name]
[docs] @staticmethod def load_plugins(plugin_dir: typing.Union[str, pathlib.Path]) -> None: """ Load plugins from plugin directory. :param plugin_dir: Directory to search for plugins """ full_plugin_path = pathlib.Path(settings.BASE_DIR).joinpath(plugin_dir) for plugin_filename in full_plugin_path.iterdir(): module_name = plugin_filename.stem if plugin_filename.suffix != '.py' or module_name in {'__init__', 'base'}: continue # When importing a module the class definitions are executed # This causes a call to the metaclass __init__ method which registers the plugin importlib.import_module(str(plugin_dir).replace('/', '.') + '.' + module_name)
@property def plugin_choices(cls) -> typing.List[typing.Tuple[str, str]]: return [(name, name) for name, plugin in cls._plugins.items()]