2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-06-15 19:45:46 +00:00

fix docstrings 7

This commit is contained in:
Matthias
2022-05-28 03:04:48 +02:00
parent bd4da62964
commit d3d0b76c58
6 changed files with 98 additions and 242 deletions

View File

@ -1,6 +1,4 @@
""" """JSON API for the plugin app"""
JSON API for the plugin app
"""
from django.conf import settings from django.conf import settings
from django.urls import include, re_path from django.urls import include, re_path
@ -20,7 +18,7 @@ from plugin.registry import registry
class PluginList(generics.ListAPIView): class PluginList(generics.ListAPIView):
""" API endpoint for list of PluginConfig objects """API endpoint for list of PluginConfig objects
- GET: Return a list of all PluginConfig objects - GET: Return a list of all PluginConfig objects
""" """
@ -79,7 +77,7 @@ class PluginList(generics.ListAPIView):
class PluginDetail(generics.RetrieveUpdateDestroyAPIView): class PluginDetail(generics.RetrieveUpdateDestroyAPIView):
""" API detail endpoint for PluginConfig object """API detail endpoint for PluginConfig object
get: get:
Return a single PluginConfig object Return a single PluginConfig object
@ -96,9 +94,8 @@ class PluginDetail(generics.RetrieveUpdateDestroyAPIView):
class PluginInstall(generics.CreateAPIView): class PluginInstall(generics.CreateAPIView):
""" """Endpoint for installing a new plugin"""
Endpoint for installing a new plugin
"""
queryset = PluginConfig.objects.none() queryset = PluginConfig.objects.none()
serializer_class = PluginSerializers.PluginConfigInstallSerializer serializer_class = PluginSerializers.PluginConfigInstallSerializer
@ -115,8 +112,7 @@ class PluginInstall(generics.CreateAPIView):
class PluginSettingList(generics.ListAPIView): class PluginSettingList(generics.ListAPIView):
""" """List endpoint for all plugin related settings.
List endpoint for all plugin related settings.
- read only - read only
- only accessible by staff users - only accessible by staff users
@ -140,8 +136,7 @@ class PluginSettingList(generics.ListAPIView):
class PluginSettingDetail(generics.RetrieveUpdateAPIView): class PluginSettingDetail(generics.RetrieveUpdateAPIView):
""" """Detail endpoint for a plugin-specific setting.
Detail endpoint for a plugin-specific setting.
Note that these cannot be created or deleted via the API Note that these cannot be created or deleted via the API
""" """
@ -150,13 +145,11 @@ class PluginSettingDetail(generics.RetrieveUpdateAPIView):
serializer_class = PluginSerializers.PluginSettingSerializer serializer_class = PluginSerializers.PluginSettingSerializer
def get_object(self): def get_object(self):
""" """Lookup the plugin setting object, based on the URL.
Lookup the plugin setting object, based on the URL.
The URL provides the 'slug' of the plugin, and the 'key' of the setting.
The URL provides the 'slug' of the plugin, and the 'key' of the setting.
Both the 'slug' and 'key' must be valid, else a 404 error is raised Both the 'slug' and 'key' must be valid, else a 404 error is raised
""" """
plugin_slug = self.kwargs['plugin'] plugin_slug = self.kwargs['plugin']
key = self.kwargs['key'] key = self.kwargs['key']

View File

@ -1,6 +1,4 @@
""" """Import helper for events"""
Import helper for events
"""
from plugin.base.event.events import (process_event, register_event, from plugin.base.event.events import (process_event, register_event,
trigger_event) trigger_event)

View File

@ -1,6 +1,5 @@
""" """Helpers for plugin app"""
Helpers for plugin app
"""
import inspect import inspect
import logging import logging
import os import os
@ -20,9 +19,8 @@ logger = logging.getLogger('inventree')
# region logging / errors # region logging / errors
class IntegrationPluginError(Exception): class IntegrationPluginError(Exception):
""" """Error that encapsulates another error and adds the path / reference of the raising plugin"""
Error that encapsulates another error and adds the path / reference of the raising plugin
"""
def __init__(self, path, message): def __init__(self, path, message):
self.path = path self.path = path
self.message = message self.message = message
@ -32,24 +30,20 @@ class IntegrationPluginError(Exception):
class MixinImplementationError(ValueError): class MixinImplementationError(ValueError):
""" """Error if mixin was implemented wrong in plugin
Error if mixin was implemented wrong in plugin
Mostly raised if constant is missing Mostly raised if constant is missing
""" """
pass pass
class MixinNotImplementedError(NotImplementedError): class MixinNotImplementedError(NotImplementedError):
""" """Error if necessary mixin function was not overwritten"""
Error if necessary mixin function was not overwritten
"""
pass pass
def log_error(error, reference: str = 'general'): def log_error(error, reference: str = 'general'):
""" """Log an plugin error"""
Log an plugin error
"""
from plugin import registry from plugin import registry
# make sure the registry is set up # make sure the registry is set up
@ -61,9 +55,7 @@ def log_error(error, reference: str = 'general'):
def handle_error(error, do_raise: bool = True, do_log: bool = True, log_name: str = ''): def handle_error(error, do_raise: bool = True, do_log: bool = True, log_name: str = ''):
""" """Handles an error and casts it as an IntegrationPluginError"""
Handles an error and casts it as an IntegrationPluginError
"""
package_path = traceback.extract_tb(error.__traceback__)[-1].filename package_path = traceback.extract_tb(error.__traceback__)[-1].filename
install_path = sysconfig.get_paths()["purelib"] install_path = sysconfig.get_paths()["purelib"]
try: try:
@ -99,9 +91,7 @@ def handle_error(error, do_raise: bool = True, do_log: bool = True, log_name: st
# region git-helpers # region git-helpers
def get_git_log(path): def get_git_log(path):
""" """Get dict with info of the last commit to file named in path"""
Get dict with info of the last commit to file named in path
"""
from plugin import registry from plugin import registry
output = None output = None
@ -122,8 +112,7 @@ def get_git_log(path):
def check_git_version(): def check_git_version():
"""returns if the current git version supports modern features""" """Returns if the current git version supports modern features"""
# get version string # get version string
try: try:
output = str(subprocess.check_output(['git', '--version'], cwd=os.path.dirname(settings.BASE_DIR)), 'utf-8') output = str(subprocess.check_output(['git', '--version'], cwd=os.path.dirname(settings.BASE_DIR)), 'utf-8')
@ -143,13 +132,11 @@ def check_git_version():
class GitStatus: class GitStatus:
""" """Class for resolving git gpg singing state"""
Class for resolving git gpg singing state
"""
class Definition: class Definition:
""" """Definition of a git gpg sing state"""
Definition of a git gpg sing state
"""
key: str = 'N' key: str = 'N'
status: int = 2 status: int = 2
msg: str = '' msg: str = ''
@ -172,8 +159,7 @@ class GitStatus:
# region plugin finders # region plugin finders
def get_modules(pkg): def get_modules(pkg):
"""get all modules in a package""" """Get all modules in a package"""
context = {} context = {}
for loader, name, ispkg in pkgutil.walk_packages(pkg.__path__): for loader, name, ispkg in pkgutil.walk_packages(pkg.__path__):
try: try:
@ -195,18 +181,16 @@ def get_modules(pkg):
def get_classes(module): def get_classes(module):
"""get all classes in a given module""" """Get all classes in a given module"""
return inspect.getmembers(module, inspect.isclass) return inspect.getmembers(module, inspect.isclass)
def get_plugins(pkg, baseclass): def get_plugins(pkg, baseclass):
""" """Return a list of all modules under a given package.
Return a list of all modules under a given package.
- Modules must be a subclass of the provided 'baseclass' - Modules must be a subclass of the provided 'baseclass'
- Modules must have a non-empty NAME parameter - Modules must have a non-empty NAME parameter
""" """
plugins = [] plugins = []
modules = get_modules(pkg) modules = get_modules(pkg)
@ -225,10 +209,7 @@ def get_plugins(pkg, baseclass):
# region templates # region templates
def render_template(plugin, template_file, context=None): def render_template(plugin, template_file, context=None):
""" """Locate and render a template file, available in the global template context."""
Locate and render a template file, available in the global template context.
"""
try: try:
tmp = template.loader.get_template(template_file) tmp = template.loader.get_template(template_file)
except template.TemplateDoesNotExist: except template.TemplateDoesNotExist:
@ -247,10 +228,7 @@ def render_template(plugin, template_file, context=None):
def render_text(text, context=None): def render_text(text, context=None):
""" """Locate a raw string with provided context"""
Locate a raw string with provided context
"""
ctx = template.Context(context) ctx = template.Context(context)
return template.Template(text).render(ctx) return template.Template(text).render(ctx)

View File

@ -1,6 +1,4 @@
""" """Plugin model definitions"""
Plugin model definitions
"""
import warnings import warnings
@ -14,8 +12,7 @@ from plugin import InvenTreePlugin, registry
class MetadataMixin(models.Model): class MetadataMixin(models.Model):
""" """Model mixin class which adds a JSON metadata field to a model,
Model mixin class which adds a JSON metadata field to a model,
for use by any (and all) plugins. for use by any (and all) plugins.
The intent of this mixin is to provide a metadata field on a model instance, The intent of this mixin is to provide a metadata field on a model instance,
@ -37,8 +34,7 @@ class MetadataMixin(models.Model):
) )
def get_metadata(self, key: str, backup_value=None): def get_metadata(self, key: str, backup_value=None):
""" """Finds metadata for this model instance, using the provided key for lookup
Finds metadata for this model instance, using the provided key for lookup
Args: Args:
key: String key for requesting metadata. e.g. if a plugin is accessing the metadata, the plugin slug should be used key: String key for requesting metadata. e.g. if a plugin is accessing the metadata, the plugin slug should be used
@ -46,22 +42,19 @@ class MetadataMixin(models.Model):
Returns: Returns:
Python dict object containing requested metadata. If no matching metadata is found, returns None Python dict object containing requested metadata. If no matching metadata is found, returns None
""" """
if self.metadata is None: if self.metadata is None:
return backup_value return backup_value
return self.metadata.get(key, backup_value) return self.metadata.get(key, backup_value)
def set_metadata(self, key: str, data, commit=True): def set_metadata(self, key: str, data, commit=True):
""" """Save the provided metadata under the provided key.
Save the provided metadata under the provided key.
Args: Args:
key: String key for saving metadata key: String key for saving metadata
data: Data object to save - must be able to be rendered as a JSON string data: Data object to save - must be able to be rendered as a JSON string
overwrite: If true, existing metadata with the provided key will be overwritten. If false, a merge will be attempted overwrite: If true, existing metadata with the provided key will be overwritten. If false, a merge will be attempted
""" """
if self.metadata is None: if self.metadata is None:
# Handle a null field value # Handle a null field value
self.metadata = {} self.metadata = {}
@ -73,14 +66,14 @@ class MetadataMixin(models.Model):
class PluginConfig(models.Model): class PluginConfig(models.Model):
""" """A PluginConfig object holds settings for plugins.
A PluginConfig object holds settings for plugins.
Attributes: Attributes:
key: slug of the plugin (this must be unique across all installed plugins!) key: slug of the plugin (this must be unique across all installed plugins!)
name: PluginName of the plugin - serves for a manual double check if the right plugin is used name: PluginName of the plugin - serves for a manual double check if the right plugin is used
active: Should the plugin be loaded? active: Should the plugin be loaded?
""" """
class Meta: class Meta:
verbose_name = _("Plugin Configuration") verbose_name = _("Plugin Configuration")
verbose_name_plural = _("Plugin Configurations") verbose_name_plural = _("Plugin Configurations")
@ -123,10 +116,7 @@ class PluginConfig(models.Model):
# functions # functions
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
""" """Override to set original state of the plugin-config instance"""
Override to set original state of the plugin-config instance
"""
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.__org_active = self.active self.__org_active = self.active
@ -145,9 +135,7 @@ class PluginConfig(models.Model):
} }
def save(self, force_insert=False, force_update=False, *args, **kwargs): def save(self, force_insert=False, force_update=False, *args, **kwargs):
""" """Extend save method to reload plugins if the 'active' status changes"""
Extend save method to reload plugins if the 'active' status changes
"""
reload = kwargs.pop('no_reload', False) # check if no_reload flag is set reload = kwargs.pop('no_reload', False) # check if no_reload flag is set
ret = super().save(force_insert, force_update, *args, **kwargs) ret = super().save(force_insert, force_update, *args, **kwargs)
@ -163,9 +151,7 @@ class PluginConfig(models.Model):
class PluginSetting(common.models.BaseInvenTreeSetting): class PluginSetting(common.models.BaseInvenTreeSetting):
""" """This model represents settings for individual plugins"""
This model represents settings for individual plugins
"""
class Meta: class Meta:
unique_together = [ unique_together = [
@ -182,8 +168,7 @@ class PluginSetting(common.models.BaseInvenTreeSetting):
@classmethod @classmethod
def get_setting_definition(cls, key, **kwargs): def get_setting_definition(cls, key, **kwargs):
""" """In the BaseInvenTreeSetting class, we have a class attribute named 'SETTINGS',
In the BaseInvenTreeSetting class, we have a class attribute named 'SETTINGS',
which is a dict object that fully defines all the setting parameters. which is a dict object that fully defines all the setting parameters.
Here, unlike the BaseInvenTreeSetting, we do not know the definitions of all settings Here, unlike the BaseInvenTreeSetting, we do not know the definitions of all settings
@ -209,20 +194,14 @@ class PluginSetting(common.models.BaseInvenTreeSetting):
return super().get_setting_definition(key, **kwargs) return super().get_setting_definition(key, **kwargs)
def get_kwargs(self): def get_kwargs(self):
""" """Explicit kwargs required to uniquely identify a particular setting object, in addition to the 'key' parameter"""
Explicit kwargs required to uniquely identify a particular setting object,
in addition to the 'key' parameter
"""
return { return {
'plugin': self.plugin, 'plugin': self.plugin,
} }
class NotificationUserSetting(common.models.BaseInvenTreeSetting): class NotificationUserSetting(common.models.BaseInvenTreeSetting):
""" """This model represents notification settings for a user"""
This model represents notification settings for a user
"""
class Meta: class Meta:
unique_together = [ unique_together = [
@ -238,11 +217,7 @@ class NotificationUserSetting(common.models.BaseInvenTreeSetting):
return super().get_setting_definition(key, **kwargs) return super().get_setting_definition(key, **kwargs)
def get_kwargs(self): def get_kwargs(self):
""" """Explicit kwargs required to uniquely identify a particular setting object, in addition to the 'key' parameter"""
Explicit kwargs required to uniquely identify a particular setting object,
in addition to the 'key' parameter
"""
return { return {
'method': self.method, 'method': self.method,
'user': self.user, 'user': self.user,

View File

@ -1,7 +1,5 @@
# -*- coding: utf-8 -*- """Base Class for InvenTree plugins"""
"""
Base Class for InvenTree plugins
"""
import inspect import inspect
import logging import logging
import os import os
@ -55,24 +53,18 @@ class MetaBase:
return value return value
def plugin_name(self): def plugin_name(self):
""" """Name of plugin"""
Name of plugin
"""
return self.get_meta_value('NAME', 'PLUGIN_NAME') return self.get_meta_value('NAME', 'PLUGIN_NAME')
@property @property
def name(self): def name(self):
""" """Name of plugin"""
Name of plugin
"""
return self.plugin_name() return self.plugin_name()
def plugin_slug(self): def plugin_slug(self):
""" """Slug of plugin
Slug of plugin
If not set plugin name slugified
"""
If not set plugin name slugified"""
slug = self.get_meta_value('SLUG', 'PLUGIN_SLUG', None) slug = self.get_meta_value('SLUG', 'PLUGIN_SLUG', None)
if not slug: if not slug:
slug = self.plugin_name() slug = self.plugin_name()
@ -81,16 +73,11 @@ class MetaBase:
@property @property
def slug(self): def slug(self):
""" """Slug of plugin"""
Slug of plugin
"""
return self.plugin_slug() return self.plugin_slug()
def plugin_title(self): def plugin_title(self):
""" """Title of plugin"""
Title of plugin
"""
title = self.get_meta_value('TITLE', 'PLUGIN_TITLE', None) title = self.get_meta_value('TITLE', 'PLUGIN_TITLE', None)
if title: if title:
return title return title
@ -98,16 +85,11 @@ class MetaBase:
@property @property
def human_name(self): def human_name(self):
""" """Human readable name of plugin"""
Human readable name of plugin
"""
return self.plugin_title() return self.plugin_title()
def plugin_config(self): def plugin_config(self):
""" """Return the PluginConfig object associated with this plugin"""
Return the PluginConfig object associated with this plugin
"""
try: try:
import plugin.models import plugin.models
@ -121,10 +103,7 @@ class MetaBase:
return cfg return cfg
def is_active(self): def is_active(self):
""" """Return True if this plugin is currently active"""
Return True if this plugin is currently active
"""
cfg = self.plugin_config() cfg = self.plugin_config()
if cfg: if cfg:
@ -134,9 +113,7 @@ class MetaBase:
class MixinBase: class MixinBase:
""" """Base set of mixin functions and mechanisms"""
Base set of mixin functions and mechanisms
"""
def __init__(self, *args, **kwargs) -> None: def __init__(self, *args, **kwargs) -> None:
self._mixinreg = {} self._mixinreg = {}
@ -144,15 +121,11 @@ class MixinBase:
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
def mixin(self, key): def mixin(self, key):
""" """Check if mixin is registered"""
Check if mixin is registered
"""
return key in self._mixins return key in self._mixins
def mixin_enabled(self, key): def mixin_enabled(self, key):
""" """Check if mixin is registered, enabled and ready"""
Check if mixin is registered, enabled and ready
"""
if self.mixin(key): if self.mixin(key):
fnc_name = self._mixins.get(key) fnc_name = self._mixins.get(key)
@ -164,18 +137,12 @@ class MixinBase:
return False return False
def add_mixin(self, key: str, fnc_enabled=True, cls=None): def add_mixin(self, key: str, fnc_enabled=True, cls=None):
""" """Add a mixin to the plugins registry"""
Add a mixin to the plugins registry
"""
self._mixins[key] = fnc_enabled self._mixins[key] = fnc_enabled
self.setup_mixin(key, cls=cls) self.setup_mixin(key, cls=cls)
def setup_mixin(self, key, cls=None): def setup_mixin(self, key, cls=None):
""" """Define mixin details for the current mixin -> provides meta details for all active mixins"""
Define mixin details for the current mixin -> provides meta details for all active mixins
"""
# get human name # get human name
human_name = getattr(cls.MixinMeta, 'MIXIN_NAME', key) if cls and hasattr(cls, 'MixinMeta') else key human_name = getattr(cls.MixinMeta, 'MIXIN_NAME', key) if cls and hasattr(cls, 'MixinMeta') else key
@ -187,10 +154,7 @@ class MixinBase:
@property @property
def registered_mixins(self, with_base: bool = False): def registered_mixins(self, with_base: bool = False):
""" """Get all registered mixins for the plugin"""
Get all registered mixins for the plugin
"""
mixins = getattr(self, '_mixinreg', None) mixins = getattr(self, '_mixinreg', None)
if mixins: if mixins:
# filter out base # filter out base
@ -202,8 +166,7 @@ class MixinBase:
class InvenTreePlugin(MixinBase, MetaBase): class InvenTreePlugin(MixinBase, MetaBase):
""" """The InvenTreePlugin class is used to integrate with 3rd party software
The InvenTreePlugin class is used to integrate with 3rd party software
DO NOT USE THIS DIRECTLY, USE plugin.InvenTreePlugin DO NOT USE THIS DIRECTLY, USE plugin.InvenTreePlugin
""" """
@ -226,9 +189,7 @@ class InvenTreePlugin(MixinBase, MetaBase):
# region properties # region properties
@property @property
def description(self): def description(self):
""" """Description of plugin"""
Description of plugin
"""
description = getattr(self, 'DESCRIPTION', None) description = getattr(self, 'DESCRIPTION', None)
if not description: if not description:
description = self.plugin_name() description = self.plugin_name()
@ -236,9 +197,7 @@ class InvenTreePlugin(MixinBase, MetaBase):
@property @property
def author(self): def author(self):
""" """Author of plugin - either from plugin settings or git"""
Author of plugin - either from plugin settings or git
"""
author = getattr(self, 'AUTHOR', None) author = getattr(self, 'AUTHOR', None)
if not author: if not author:
author = self.package.get('author') author = self.package.get('author')
@ -248,9 +207,7 @@ class InvenTreePlugin(MixinBase, MetaBase):
@property @property
def pub_date(self): def pub_date(self):
""" """Publishing date of plugin - either from plugin settings or git"""
Publishing date of plugin - either from plugin settings or git
"""
pub_date = getattr(self, 'PUBLISH_DATE', None) pub_date = getattr(self, 'PUBLISH_DATE', None)
if not pub_date: if not pub_date:
pub_date = self.package.get('date') pub_date = self.package.get('date')
@ -262,77 +219,57 @@ class InvenTreePlugin(MixinBase, MetaBase):
@property @property
def version(self): def version(self):
""" """Version of plugin"""
Version of plugin
"""
version = getattr(self, 'VERSION', None) version = getattr(self, 'VERSION', None)
return version return version
@property @property
def website(self): def website(self):
""" """Website of plugin - if set else None"""
Website of plugin - if set else None
"""
website = getattr(self, 'WEBSITE', None) website = getattr(self, 'WEBSITE', None)
return website return website
@property @property
def license(self): def license(self):
""" """License of plugin"""
License of plugin
"""
lic = getattr(self, 'LICENSE', None) lic = getattr(self, 'LICENSE', None)
return lic return lic
# endregion # endregion
@property @property
def _is_package(self): def _is_package(self):
""" """Is the plugin delivered as a package"""
Is the plugin delivered as a package
"""
return getattr(self, 'is_package', False) return getattr(self, 'is_package', False)
@property @property
def is_sample(self): def is_sample(self):
""" """Is this plugin part of the samples?"""
Is this plugin part of the samples?
"""
path = str(self.package_path) path = str(self.package_path)
return path.startswith('plugin/samples/') return path.startswith('plugin/samples/')
@property @property
def package_path(self): def package_path(self):
""" """Path to the plugin"""
Path to the plugin
"""
if self._is_package: if self._is_package:
return self.__module__ # pragma: no cover return self.__module__ # pragma: no cover
return pathlib.Path(self.def_path).relative_to(settings.BASE_DIR) return pathlib.Path(self.def_path).relative_to(settings.BASE_DIR)
@property @property
def settings_url(self): def settings_url(self):
""" """URL to the settings panel for this plugin"""
URL to the settings panel for this plugin
"""
return f'{reverse("settings")}#select-plugin-{self.slug}' return f'{reverse("settings")}#select-plugin-{self.slug}'
# region package info # region package info
def _get_package_commit(self): def _get_package_commit(self):
""" """Get last git commit for the plugin"""
Get last git commit for the plugin
"""
return get_git_log(self.def_path) return get_git_log(self.def_path)
def _get_package_metadata(self): def _get_package_metadata(self):
""" """Get package metadata for plugin"""
Get package metadata for plugin
"""
return {} # pragma: no cover # TODO add usage for package metadata return {} # pragma: no cover # TODO add usage for package metadata
def define_package(self): def define_package(self):
""" """Add package info of the plugin into plugins context"""
Add package info of the plugin into plugins context
"""
package = self._get_package_metadata() if self._is_package else self._get_package_commit() package = self._get_package_metadata() if self._is_package else self._get_package_commit()
# process date # process date

View File

@ -30,9 +30,7 @@ logger = logging.getLogger('inventree')
class PluginsRegistry: class PluginsRegistry:
""" """The PluginsRegistry class"""
The PluginsRegistry class
"""
def __init__(self) -> None: def __init__(self) -> None:
# plugin registry # plugin registry
@ -54,10 +52,7 @@ class PluginsRegistry:
self.mixins_settings = {} self.mixins_settings = {}
def get_plugin(self, slug): def get_plugin(self, slug):
""" """Lookup plugin by slug (unique key)."""
Lookup plugin by slug (unique key).
"""
if slug not in self.plugins: if slug not in self.plugins:
logger.warning(f"Plugin registry has no record of plugin '{slug}'") logger.warning(f"Plugin registry has no record of plugin '{slug}'")
return None return None
@ -65,15 +60,13 @@ class PluginsRegistry:
return self.plugins[slug] return self.plugins[slug]
def call_plugin_function(self, slug, func, *args, **kwargs): def call_plugin_function(self, slug, func, *args, **kwargs):
""" """Call a member function (named by 'func') of the plugin named by 'slug'.
Call a member function (named by 'func') of the plugin named by 'slug'.
As this is intended to be run by the background worker, As this is intended to be run by the background worker,
we do not perform any try/except here. we do not perform any try/except here.
Instead, any error messages are returned to the worker. Instead, any error messages are returned to the worker.
""" """
plugin = self.get_plugin(slug) plugin = self.get_plugin(slug)
if not plugin: if not plugin:
@ -86,9 +79,7 @@ class PluginsRegistry:
# region public functions # region public functions
# region loading / unloading # region loading / unloading
def load_plugins(self): def load_plugins(self):
""" """Load and activate all IntegrationPlugins"""
Load and activate all IntegrationPlugins
"""
if not settings.PLUGINS_ENABLED: if not settings.PLUGINS_ENABLED:
# Plugins not enabled, do nothing # Plugins not enabled, do nothing
return # pragma: no cover return # pragma: no cover
@ -143,10 +134,7 @@ class PluginsRegistry:
logger.info('Finished loading plugins') logger.info('Finished loading plugins')
def unload_plugins(self): def unload_plugins(self):
""" """Unload and deactivate all IntegrationPlugins"""
Unload and deactivate all IntegrationPlugins
"""
if not settings.PLUGINS_ENABLED: if not settings.PLUGINS_ENABLED:
# Plugins not enabled, do nothing # Plugins not enabled, do nothing
return # pragma: no cover return # pragma: no cover
@ -170,10 +158,7 @@ class PluginsRegistry:
logger.info('Finished unloading plugins') logger.info('Finished unloading plugins')
def reload_plugins(self): def reload_plugins(self):
""" """Safely reload IntegrationPlugins"""
Safely reload IntegrationPlugins
"""
# Do not reload whe currently loading # Do not reload whe currently loading
if self.is_loading: if self.is_loading:
return # pragma: no cover return # pragma: no cover
@ -188,7 +173,6 @@ class PluginsRegistry:
def collect_plugins(self): def collect_plugins(self):
"""Collect plugins from all possible ways of loading""" """Collect plugins from all possible ways of loading"""
if not settings.PLUGINS_ENABLED: if not settings.PLUGINS_ENABLED:
# Plugins not enabled, do nothing # Plugins not enabled, do nothing
return # pragma: no cover return # pragma: no cover
@ -217,10 +201,7 @@ class PluginsRegistry:
logger.info(", ".join([a.__module__ for a in self.plugin_modules])) logger.info(", ".join([a.__module__ for a in self.plugin_modules]))
def install_plugin_file(self): def install_plugin_file(self):
""" """Make sure all plugins are installed in the current enviroment"""
Make sure all plugins are installed in the current enviroment
"""
if settings.PLUGIN_FILE_CHECKED: if settings.PLUGIN_FILE_CHECKED:
logger.info('Plugin file was already checked') logger.info('Plugin file was already checked')
return True return True
@ -241,9 +222,7 @@ class PluginsRegistry:
# region registry functions # region registry functions
def with_mixin(self, mixin: str, active=None): def with_mixin(self, mixin: str, active=None):
""" """Returns reference to all plugins that have a specified mixin enabled"""
Returns reference to all plugins that have a specified mixin enabled
"""
result = [] result = []
for plugin in self.plugins.values(): for plugin in self.plugins.values():
@ -264,14 +243,12 @@ class PluginsRegistry:
# region general internal loading /activating / deactivating / deloading # region general internal loading /activating / deactivating / deloading
def _init_plugins(self, disabled=None): def _init_plugins(self, disabled=None):
""" """Initialise all found plugins
Initialise all found plugins
:param disabled: loading path of disabled app, defaults to None :param disabled: loading path of disabled app, defaults to None
:type disabled: str, optional :type disabled: str, optional
:raises error: IntegrationPluginError :raises error: IntegrationPluginError
""" """
from plugin.models import PluginConfig from plugin.models import PluginConfig
logger.info('Starting plugin initialisation') logger.info('Starting plugin initialisation')
@ -335,8 +312,7 @@ class PluginsRegistry:
self.plugins_inactive[plug_key] = plugin_db_setting # pragma: no cover self.plugins_inactive[plug_key] = plugin_db_setting # pragma: no cover
def _activate_plugins(self, force_reload=False): def _activate_plugins(self, force_reload=False):
""" """Run activation functions for all plugins
Run activation functions for all plugins
:param force_reload: force reload base apps, defaults to False :param force_reload: force reload base apps, defaults to False
:type force_reload: bool, optional :type force_reload: bool, optional
@ -351,7 +327,6 @@ class PluginsRegistry:
def _deactivate_plugins(self): def _deactivate_plugins(self):
"""Run deactivation functions for all plugins""" """Run deactivation functions for all plugins"""
self.deactivate_plugin_app() self.deactivate_plugin_app()
self.deactivate_plugin_schedule() self.deactivate_plugin_schedule()
self.deactivate_plugin_settings() self.deactivate_plugin_settings()
@ -425,15 +400,14 @@ class PluginsRegistry:
logger.warning("activate_integration_schedule failed, database not ready") logger.warning("activate_integration_schedule failed, database not ready")
def deactivate_plugin_schedule(self): def deactivate_plugin_schedule(self):
""" """Deactivate ScheduleMixin
Deactivate ScheduleMixin
currently nothing is done currently nothing is done
""" """
pass pass
def activate_plugin_app(self, plugins, force_reload=False): def activate_plugin_app(self, plugins, force_reload=False):
""" """Activate AppMixin plugins - add custom apps and reload
Activate AppMixin plugins - add custom apps and reload
:param plugins: list of IntegrationPlugins that should be installed :param plugins: list of IntegrationPlugins that should be installed
:type plugins: dict :type plugins: dict
@ -471,9 +445,10 @@ class PluginsRegistry:
self._update_urls() self._update_urls()
def _reregister_contrib_apps(self): def _reregister_contrib_apps(self):
"""fix reloading of contrib apps - models and admin """Fix reloading of contrib apps - models and admin
this is needed if plugins were loaded earlier and then reloaded as models and admins rely on imports
those register models and admin in their respective objects (e.g. admin.site for admin) This is needed if plugins were loaded earlier and then reloaded as models and admins rely on imports.
Those register models and admin in their respective objects (e.g. admin.site for admin).
""" """
for plugin_path in self.installed_apps: for plugin_path in self.installed_apps:
try: try:
@ -503,8 +478,9 @@ class PluginsRegistry:
reload(app_config.module.admin) reload(app_config.module.admin)
def _get_plugin_path(self, plugin): def _get_plugin_path(self, plugin):
"""parse plugin path """Parse plugin path
the input can be eiter:
The input can be eiter:
- a local file / dir - a local file / dir
- a package - a package
""" """
@ -518,7 +494,6 @@ class PluginsRegistry:
def deactivate_plugin_app(self): def deactivate_plugin_app(self):
"""Deactivate AppMixin plugins - some magic required""" """Deactivate AppMixin plugins - some magic required"""
# unregister models from admin # unregister models from admin
for plugin_path in self.installed_apps: for plugin_path in self.installed_apps:
models = [] # the modelrefs need to be collected as poping an item in a iter is not welcomed models = [] # the modelrefs need to be collected as poping an item in a iter is not welcomed
@ -601,9 +576,9 @@ class PluginsRegistry:
self.is_loading = False self.is_loading = False
def _try_reload(self, cmd, *args, **kwargs): def _try_reload(self, cmd, *args, **kwargs):
""" """Wrapper to try reloading the apps
wrapper to try reloading the apps
throws an custom error that gets handled by the loading function Throws an custom error that gets handled by the loading function
""" """
try: try:
cmd(*args, **kwargs) cmd(*args, **kwargs)
@ -617,5 +592,5 @@ registry = PluginsRegistry()
def call_function(plugin_name, function_name, *args, **kwargs): def call_function(plugin_name, function_name, *args, **kwargs):
""" Global helper function to call a specific member function of a plugin """ """Global helper function to call a specific member function of a plugin"""
return registry.call_plugin_function(plugin_name, function_name, *args, **kwargs) return registry.call_plugin_function(plugin_name, function_name, *args, **kwargs)