InvenTree/InvenTree/plugin/plugins.py
2021-11-15 02:10:43 +01:00

119 lines
3.2 KiB
Python

# -*- coding: utf-8 -*-
"""general functions for plugin handeling"""
import inspect
import importlib
import pkgutil
import logging
from django.conf import settings
from django.core.exceptions import AppRegistryNotReady
# Action plugins
import plugin.builtin.action as action
from plugin.action import ActionPlugin
# Integration
from plugin.integration import IntegrationPluginBase
logger = logging.getLogger("inventree")
def iter_namespace(pkg):
"""get all modules in a package"""
return pkgutil.iter_modules(pkg.__path__, pkg.__name__ + ".")
def get_modules(pkg, recursive: bool = False):
"""get all modules in a package"""
if not recursive:
return [importlib.import_module(name) for finder, name, ispkg in iter_namespace(pkg)]
context = {}
for loader, name, ispkg in pkgutil.walk_packages(pkg.__path__):
try:
module = loader.find_module(name).load_module(name)
pkg_names = getattr(module, '__all__', None)
for k, v in vars(module).items():
if not k.startswith('_') and (pkg_names is None or k in pkg_names):
context[k] = v
context[name] = module
except AppRegistryNotReady:
pass
return [v for k, v in context.items()]
def get_classes(module):
"""get all classes in a given module"""
return inspect.getmembers(module, inspect.isclass)
def get_plugins(pkg, baseclass, recursive: bool = False):
"""
Return a list of all modules under a given package.
- Modules must be a subclass of the provided 'baseclass'
- Modules must have a non-empty PLUGIN_NAME parameter
"""
plugins = []
modules = get_modules(pkg, recursive)
# Iterate through each module in the package
for mod in modules:
# Iterate through each class in the module
for item in get_classes(mod):
plugin = item[1]
if issubclass(plugin, baseclass) and plugin.PLUGIN_NAME:
plugins.append(plugin)
return plugins
def load_plugins(name: str, cls, module=None):
"""general function to load a plugin class
:param name: name of the plugin for logs
:type name: str
:param module: module from which the plugins should be loaded
:return: class of the to-be-loaded plugin
"""
logger.debug("Loading %s plugins", name)
plugins = get_plugins(module, cls) if module else settings.PLUGINS
if len(plugins) > 0:
logger.info("Discovered %i %s plugins:", len(plugins), name)
for plugin in plugins:
logger.debug(" - %s", plugin.PLUGIN_NAME)
return plugins
def load_action_plugins():
"""
Return a list of all registered action plugins
"""
return load_plugins('action', ActionPlugin, module=action)
def load_integration_plugins():
"""
Return a list of all registered integration plugins
"""
return load_plugins('integration', IntegrationPluginBase)
def load_barcode_plugins():
"""
Return a list of all registered barcode plugins
"""
from barcodes import plugins as BarcodePlugins
from barcodes.barcode import BarcodePlugin
return load_plugins('barcode', BarcodePlugin, module=BarcodePlugins)