You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
shepherd-agent/shepherd/agent/plugin.py

100 lines
3.0 KiB

import importlib
import inspect
import logging
import sys
import os
log = logging.getLogger(__name__)
class PluginLoadError(Exception):
pass
def plugin():
pass
def plugin_function():
pass
def plugin_hook():
pass
def plugin_attachment(hookname):
pass
class PluginInterface():
def __init__(self):
self._confspec = None
@property
def confspec(self):
return self._confspec
def find_plugins(plugin_names, plugin_dir=None):
"""
Looks for the list of plugin names supplied and returns their classes.
Will first try for plugin modules and packages locally located in ``shepherd.plugins``,
then for modules and packages prefixed ``shepherd_`` located in the supplied ``plugin_dir``
and lastly in the global import path.
Args:
plugin_names: List of plugin names to try and load
plugin_dir: optional search path
Returns:
Dict of plugin classes, with their names as keys
"""
plugin_classes = {}
for plugin_name in plugin_names:
# First look for core plugins, then the plugin_dir, then in the general import path
# for custom ones prefixed with "shepherd_"
try:
# mod = importlib.import_module("shepherd.plugins." + plugin_name)
mod = importlib.import_module('.'+plugin_name, "shepherd.plugins")
# TODO - ModuleNotFoundError is also triggered here if the plugin has a dependancy
# that can't be found
except ModuleNotFoundError:
try:
if plugin_dir:
if os.path.isdir(plugin_dir):
sys.path.append(plugin_dir)
mod = importlib.import_module("shepherd_" + plugin_name)
sys.path.remove(plugin_dir)
else:
raise PluginLoadError("plugin_dir is not a valid directory")
else:
mod = importlib.import_module("shepherd_" + plugin_name)
except ModuleNotFoundError:
raise PluginLoadError("Could not find plugin "+plugin_name)
# Scan imported module for Plugin subclass
def is_module_plugin(member, module=mod):
return (inspect.isclass(member) and member.__module__ ==
module.__name__ and issubclass(member, Plugin))
class_list = inspect.getmembers(mod, is_module_plugin)
if class_list:
if len(class_list) > 1:
log.warning(
F"Plugin module {mod.__name__} has more than one shepherd.Plugin subclass.")
_, plugin_classes[plugin_name] = class_list[0]
log.info(F"Loading plugin {plugin_classes[plugin_name].__name__}"
" from module {mod.__name__}")
else:
raise PluginLoadError("Imported shepherd plugin modules must contain a"
" subclass of shepherd.plugin.Plugin, such as"
" shepherd.plugin.SimplePlugin")
return plugin_classes